Add deployment bridge sub-repository (#25)

* Added deployment-bridge from tags/1.0.0

* Removed Contributing, Licence, Code of Conduct, updated links in readme.
This commit is contained in:
Przemyslaw Rzad 2019-05-08 13:51:56 +02:00 committed by GitHub
parent d656025378
commit 0447dd1a78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 1531 additions and 0 deletions

7
deployment-bridge/.gitignore vendored Normal file

@ -0,0 +1,7 @@
*.retry
hosts.yml
hosts
*.log
Vagrantfile
vagrant-hosts.yml
.vagrant

@ -0,0 +1,51 @@
# Ansible playbooks for deploying cross-chain bridges
## Bridge Overview
The POA Bridge allows users to transfer assets between two chains in the Ethereum ecosystem. It is composed of several elements which are located in different POA Network repositories:
**Bridge Elements**
1. Deployment Playbooks. Configuration management instructions for validator nodes contained in this repository.
2. [Bridge Smart Contracts](https://github.com/poanetwork/poa-bridge-contracts). Solidity contracts used to manage bridge validators, collect signatures, and confirm asset relay and disposal.
3. [Token Bridge](https://github.com/poanetwork/token-bridge). The token bridge oracle written in NodeJS.
4. [Bridge UI Application](https://github.com/poanetwork/bridge-ui). A DApp interface to transfer tokens and coins between chains.
5. [Bridge Monitor](https://github.com/poanetwork/bridge-monitor). A tool for checking balances and unprocessed events in bridged networks.
## Playbooks Overview
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 deployment are located in the [bridge-nodejs](bridge-nodejs) folder.
### Rust Bridge Playbooks
The Rust bridge is not currently in production, but an Ansible playbook is developed for this implementation. It is available in the [upgradable-wo-parity](upgradable-wo-parity)folder.
## 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.
## Configuration
Please see the [bridge-nodejs README](bridge-nodejs/README.md) for configuration and execution details.
## 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]
```
## Contributing
See the [CONTRIBUTING](../CONTRIBUTING.md) document for contribution, testing and pull request protocol.
## License
[![License: LGPL v3.0](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)
This project is licensed under the GNU Lesser General Public License v3.0. See the [LICENSE](../LICENSE) file for details.

@ -0,0 +1,2 @@
hosts.yml
hosts

@ -0,0 +1,136 @@
### 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 `bridge-nodejs` folder
```
git clone https://github.com/poanetwork/deployment-bridge.git
cd deployment-bridge/bridge-nodejs
```
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 token-bridge. See https://github.com/poanetwork/token-bridge#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 POA bridge.
2.2 `bridge_repo` contains address of token-bridge repository. The default value is https://github.com/poanetwork/token-bridge.
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 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.
## 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.
```

@ -0,0 +1,7 @@
[defaults]
host_key_checking = False
stdout_callback = skippy
ANSIBLE_DEBUG=1
[ssh_connection]
pipelining=True

@ -0,0 +1,24 @@
## 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

@ -0,0 +1,24 @@
## 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

@ -0,0 +1,24 @@
## 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

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

@ -0,0 +1,17 @@
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

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

@ -0,0 +1,5 @@
{
"disable-legacy-registry": true,
"live-restore": true,
"no-new-privileges": true
}

@ -0,0 +1,14 @@
- name: restart rsyslog
service:
name: rsyslog
state: restarted
- name: restart auditd
service:
name: auditd
state: restarted
- name: restart docker
service:
name: docker
state: restarted

@ -0,0 +1,74 @@
- name: Install the gpg key for docker
apt_key:
url: "https://download.docker.com/linux/ubuntu/gpg"
state: present
- name: Install the docker repos
apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
state: present
- name: Install apt dependencies
apt:
update_cache: yes
name: "{{ item }}"
with_items:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- docker-ce
- git
- "{{ (ansible_python_interpreter | default ('python')).split('/')[-1] }}-pip"
- name: Install Docker Compose
get_url:
url: "https://github.com/docker/compose/releases/download/{{ docker_compose_version }}/docker-compose-Linux-x86_64"
dest: "/usr/local/bin/docker-compose"
force: True
owner: "root"
group: "root"
mode: "0755"
- name: Install python docker library
pip:
name: "{{ item }}"
with_items:
- docker
- docker-compose
- name: Add user to run docker-compose
user:
name: "{{ compose_service_user }}"
comment: user to run docker-compose
group: docker
createhome: yes
- name: Install auditd
apt:
name: auditd
update_cache: yes
- name: Configure auditd
blockinfile:
path: /etc/audit/audit.rules
block: |
-w /usr/bin/docker -p wa
-w /var/lib/docker -p wa
-w /etc/docker -p wa
-w /lib/systemd/system/docker.service -p wa
-w /lib/systemd/system/docker.socket -p wa
-w /etc/default/docker -p wa
-w /etc/docker/daemon.json -p wa
-w /usr/bin/docker-containerd -p wa
-w /usr/bin/docker-runc -p wa
notify: restart auditd
- name: Configure docker engine
copy:
src: daemon.json
dest: /etc/docker/daemon.json
owner: root
group: root
mode: 0640
notify: restart docker

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

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

@ -0,0 +1,5 @@
- name: Launch container
docker_service:
project_src: "{{ bridge_path }}"
state: present
build: yes

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

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

@ -0,0 +1,51 @@
- name: Slurp docker compose file
slurp:
src: "{{ bridge_path }}/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 }}/docker-compose.yml"
- name: Set the local container logs configuration file
template:
src: 30-docker.conf.j2
dest: /etc/rsyslog.d/30-docker.conf
owner: root
group: root
mode: 644
- name: Set the log configuration file to send container logs to remote server
template:
src: 35-remote-logging.conf.j2
dest: /etc/rsyslog.d/35-remote-logging.conf
owner: root
group: root
mode: 644
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: 644
- name: Discarding unwanted messages in rsyslog
blockinfile:
path: /etc/rsyslog.conf
insertbefore: "# Where to place spool and state files"
marker: "#{mark} add string to discarding unwanted messages"
content: ':msg, contains, "VALIDATOR_ADDRESS_PRIVATE_KEY" ~'
notify: restart rsyslog

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

@ -0,0 +1,28 @@
template(name="RemoteForwardFormat" type="list") {
constant(value="<")
property(name="pri")
constant(value=">")
property(name="timestamp" dateFormat="rfc3339")
constant(value=" ")
property(name="hostname")
constant(value=" ")
property(name="syslogtag")
property(name="msg" spifno1stsp="on")
property(name="msg")
}
if $programname startswith 'bridge_' or $programname startswith 'docker' 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,16 @@
/var/log/docker/*/docker.log {
rotate 5
size 1G
compress
missingok
delaycompress
copytruncate
}
/var/log/docker/*.log {
rotate 5
size 1G
compress
missingok
delaycompress
copytruncate
}

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

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

@ -0,0 +1,33 @@
- name: Get blocks
become_user: "{{ compose_service_user }}"
shell: docker-compose run --entrypoint "node scripts/getValidatorStartBlocks.js" bridge_affirmation
args:
chdir: "{{ bridge_path }}"
register: BLOCKS
- name: Write blocks
blockinfile:
path: "{{ bridge_path }}/.env"
marker: "## {mark} Calculated by scripts/getValidatorStartBlocks.js"
block: |
HOME_START_BLOCK={{ (BLOCKS.stdout | from_json).homeStartBlock }}
FOREIGN_START_BLOCK={{ (BLOCKS.stdout | from_json).foreignStartBlock }}
- name: Get validator address
become_user: "{{ compose_service_user }}"
shell: docker-compose run -e VALIDATOR_ADDRESS_PRIVATE_KEY="{{ VALIDATOR_ADDRESS_PRIVATE_KEY }}" --entrypoint "node scripts/privateKeyToAddress.js" bridge_affirmation
args:
chdir: "{{ bridge_path }}"
register: VADDRESS
- name: Set VALIDATOR_ADDRESS variable
set_fact:
VALIDATOR_ADDRESS: "{{ VADDRESS.stdout }}"
- name: Install .key config
template:
src: key.j2
dest: "/root/.key"
owner: root
group: root
mode: 0600

@ -0,0 +1,3 @@
## Validator-specific options
VALIDATOR_ADDRESS={{ VALIDATOR_ADDRESS }}
VALIDATOR_ADDRESS_PRIVATE_KEY={{ VALIDATOR_ADDRESS_PRIVATE_KEY }}

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

@ -0,0 +1,6 @@
bridge_path: "/home/{{ compose_service_user }}/bridge"
ALLOW_HTTP: no
QUEUE_URL: amqp://rabbit
REDIS_URL: redis://redis
REDIS_LOCK_TTL: 1000

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

@ -0,0 +1,42 @@
## General settings
BRIDGE_MODE={{ BRIDGE_MODE }}
## Home contract
HOME_RPC_URL={{ HOME_RPC_URL }}
HOME_BRIDGE_ADDRESS={{ HOME_BRIDGE_ADDRESS }}
HOME_POLLING_INTERVAL={{ HOME_POLLING_INTERVAL }}
## Foreign contract
FOREIGN_RPC_URL={{ FOREIGN_RPC_URL }}
FOREIGN_BRIDGE_ADDRESS={{ FOREIGN_BRIDGE_ADDRESS }}
ERC20_TOKEN_ADDRESS={{ ERC20_TOKEN_ADDRESS }}
FOREIGN_POLLING_INTERVAL={{ FOREIGN_POLLING_INTERVAL }}
## Gasprice
{% 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={{ HOME_GAS_PRICE_FALLBACK }}
{% if HOME_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %}
HOME_GAS_PRICE_UPDATE_INTERVAL={{ HOME_GAS_PRICE_UPDATE_INTERVAL }}
{% endif %}
{% if FOREIGN_GAS_PRICE_ORACLE_URL | default('') != '' %}
FOREIGN_GAS_PRICE_ORACLE_URL={{ FOREIGN_GAS_PRICE_ORACLE_URL }}
{% endif %}
{% if FOREIGN_GAS_PRICE_SPEED_TYPE | default('') != '' %}
FOREIGN_GAS_PRICE_SPEED_TYPE={{ FOREIGN_GAS_PRICE_SPEED_TYPE }}
{% endif %}
FOREIGN_GAS_PRICE_FALLBACK={{ FOREIGN_GAS_PRICE_FALLBACK }}
{% if FOREIGN_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %}
FOREIGN_GAS_PRICE_UPDATE_INTERVAL={{ FOREIGN_GAS_PRICE_UPDATE_INTERVAL }}
{% endif %}
## Transport configuration
ALLOW_HTTP={{ "yes" if ALLOW_HTTP else "no" }}
QUEUE_URL={{ QUEUE_URL }}
REDIS_URL={{ REDIS_URL }}
REDIS_LOCK_TTL={{ REDIS_LOCK_TTL }}

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

@ -0,0 +1,3 @@
bridge_path: "/home/{{ compose_service_user }}/bridge"
bridge_repo: https://github.com/poanetwork/token-bridge.git
bridge_repo_branch: master

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

@ -0,0 +1,5 @@
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.

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

@ -0,0 +1,14 @@
---
- 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

@ -0,0 +1,94 @@
#! /bin/bash
### BEGIN INIT INFO
# Provides: poabridge
# 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 if bridge_path[:1] != "/" else bridge_path }}"
#Getting path to private key file and variable name for parsing key file
keyfile="{{ keyfile_path }}"
vaddr="VALIDATOR_ADDRESS="
vkey="VALIDATOR_ADDRESS_PRIVATE_KEY="
#Parsing file content and add key to variable
while read -r line
do
case $line in
$vaddr*)
vaddr=${line#$vaddr}
;;
$vkey*)
vkey=${line#$vkey}
;;
esac
done < $keyfile
start(){
echo "Starting bridge.."
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 }}" VALIDATOR_ADDRESS=$vaddr VALIDATOR_ADDRESS_PRIVATE_KEY=$vkey /usr/local/bin/docker-compose up --detach
}
stop(){
echo "Stopping bridge.."
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v
sleep 2
}
status(){
echo "Bridge status:"
cd $WORKDIR
sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose ps
}
rebuild(){
echo "Rebuild bridge.."
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 }}" VALIDATOR_ADDRESS=$vaddr VALIDATOR_ADDRESS_PRIVATE_KEY=$vkey /usr/local/bin/docker-compose up --detach --force-recreate --no-deps --build
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
echo "Restarting bridge.."
stop
start
;;
rebuild)
rebuild
;;
*)
echo $"Usage: $0 {start|stop|restart|rebuild|status}"
exit 1
;;
esac
exit 0

@ -0,0 +1,19 @@
- 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,5 @@
hosts.yml
*.retry
temp
test.js
output.txt

@ -0,0 +1,119 @@
Bridge-specific parameters should be stored in `group_vars/$BRIDGE_NAME.yml` so that they can be easily reused by selecting suitable bridge name in `hosts.yml`. However, for one-time testing purposes, these parameters can also be set directly in `hosts.yml` alongside other node-specific parametrs.
## Details of the authority node setup
Installation consists of 2 parts:
### 1. Preparing
1. A new user without sudo access is created. By default it's named `bridgeuser`, but can be controlled by `service_user` variable in `authority_node.yml`
2. UFW is configured to allow inbound tcp connections only on ssh port (`22` by default)
3. Syslog forwarding to remote server is setup by placing a config file in `/etc/rsyslog.d/tls-client.conf` file. This is done only if `syslog_server_port` is not empty
4. Binaries and configuration files will be stored in the bridgeuser's home directory in `poa-bridge` folder, with the following structure:
```
poa-bridge/
└── bridge/
├── bridge*
├── config.toml
├── db.toml
├── password.txt
└── keys/
└── home-keystore.json
```
here `*` means executable file, `/` means folder. Parity binary is downloaded both to home-node folder and foreign-node folder in case different versions might be required.
### 2. Setting up bridge service
1. Bridge binary is downloaded from url specified in `bridge_bin_url` variable (default value is set in `roles/bridge/defaults/main.yml`). Binary's sha256-checksum is validated against the value from `bridge_bin_sha256`. So when changing default version **both** `bridge_bin_url` and `bridge_bin_sha256` should be updated
2. Bridge `config.toml` is created based on `roles/bridge/templates/bridge.service.j2`, example:
```
keystore = "keys"
[home]
account = "0x006E27B6A72E1f34C626762F3C4761547Aff1421"
required_confirmations = 0
poll_interval = 2
rpc_host = "https://sokol.poa.network"
rpc_port = 443
password = "password.txt"
[foreign]
account = "0x006E27B6A72E1f34C626762F3C4761547Aff1421"
required_confirmations = 0
poll_interval = 2
rpc_host = "https://kovan.infura.io/mew"
rpc_port = 443
password = "password.txt"
[authorities]
accounts = []
required_signatures = 1
[transactions]
deposit_relay = { gas = 3000000, gas_price = 1000000000 }
withdraw_relay = { gas = 3000000, gas_price = 1000000000 }
withdraw_confirm = { gas = 3000000, gas_price = 1000000000 }
```
3. Database `db.toml` file is created based on `roles/bridge/db.toml.j2`, example (in this case it will be the same for all newly-created nodes):
```
home_contract_address = "0xad1dae0320717a288912ff7bae766ac87e7d14a5"
foreign_contract_address = "0xfd03be9947cbecb14a1ae8729936e23af7a0b50b"
checked_deposit_relay = 1768893
checked_withdraw_relay = 6715777
checked_withdraw_confirm = 6715777
```
**OR** `db.toml` can be copied from local machine, in this case `db_toml_location` variable should be set in `hosts.yml` to absolute path of the file
4. Bridge service is installed for `systemd` so that it auto-start on startup and auto-restarts if bridge process fails. Example of `/etc/systemd/system/bridge.service`
```
[Unit]
Description=bridge
After=network.target
[Service]
User=bridgeuser
Group=bridgeuser
WorkingDirectory=/home/bridgeuser/poa-bridge/bridge
Environment=RUST_LOG=info
ExecStart=/home/bridgeuser/poa-bridge/bridge/bridge --config /home/bridgeuser/poa-bridge/bridge/config.toml --database /home/bridgeuser/poa-bridge/bridge/db.toml
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
```
By default, restart delay is 3 seconds, this can be controlled by `restart_delay_sec` variable
5. Logs are stored in `/var/log/syslog`. If you provided `syslog_server_port` variable (in format `host:port`) in `hosts.yml` during installation, logs from syslog will be duplicated to a central syslog server for analysis and monitoring
## Useful commands
1. Restart services:
```
sudo systemctl restart bridge
```
Replace `restart` with `start` or `stop` if needed
2. Get quick status of a service:
```
sudo systemctl status bridge
```
note if it's reported `active`, `running` or `dead`
3. Tail bridge logs from `/var/log/syslog`:
```
tail -F /var/log/syslog | grep bridge
```
4. Relogin as bridge user (user without sudo access for running bridge):
```
sudo -i -u bridgeuser
```
to go back
```
exit
```
## URLs of bridge precompiled binary
Update `bridge_bin_url` and `bridge_bin_sha256` from `roles/bridge/defaults/main.yml`

@ -0,0 +1,48 @@
## How to create group_vars file for a new bridge deployment
If you deployed a new bridge and want it to be preconfigured for the future, you need to create an `.yml` file in `group_vars/` folder of this playbook.
Basically, you can use `sokol-kovan.yml` as a template:
```
### home side rpc
home_rpc_url: https://sokol.poa.network
home_rpc_port: 443
### foreign side rpc
foreign_rpc_url: https://kovan.infura.io/mew
foreign_rpc_port: 443
### bridge configs
bridge_deposit_relay_gas: 3000000
bridge_withdraw_relay_gas: 3000000
bridge_withdraw_confirm_gas: 3000000
bridge_deposit_relay_gas_price: 1000000000
bridge_withdraw_relay_gas_price: 1000000000
bridge_withdraw_confirm_gas_price: 1000000000
bridge_authorities_requires_signatures: 1
bridge_home_required_confirmations: 0
bridge_foreign_required_confirmations: 0
bridge_home_contract_address: "0x98f7b68C0Ef6A7DA0Bb0E786144A87bfEcc5cbD1"
bridge_foreign_contract_address: "0x5c29759020Fa2251B6481A3Ac1Ee507Ddbdc075c"
bridge_home_contract_deploy: 2213129
bridge_foreign_contract_deploy: 7066466
bridge_home_poll_interval: 4
bridge_foreign_poll_interval: 3
bridge_home_default_gas_price: 1000000000
bridge_foreign_gas_price_oracle_url: https://gasprice.poa.network
bridge_foreign_gas_price_timeout: 10
bridge_foreign_gas_price_speed: fast #other possible values: slow, standard, instant
bridge_foreign_default_gas_price: 21000000000
```
Let's examine available options:
* `*_rpc_url`: url of the rpc endpoint of the home-side of the bridge
* `*_rpc_port`: port to use (for https use 443)
* `bridge_*` options are directly related to the values in `config.toml` and `db.toml`, see `roles/bridge/templates/config.toml.j2` and `roles/bridge/templates/db.toml.j2` for more details.

@ -0,0 +1,49 @@
## Deploying bridge authority node
### Prerequisites
1. Launch an Ubuntu 16.04 server on your favourite hosting provider and note its IP address. You should 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
### Preparing configuration file
1. Clone this repository and go to `upgradable-wo-parity` folder
```
git clone https://github.com/poanetwork/deployment-bridge.git
cd upgradable-wo-parity
```
2. Create file `hosts.yml` from `hosts.yml.template`
```
cp hosts.yml.template hosts.yml
```
This file contains parameters specific to your node, so you need to edit it and replace/provide missing values. Let's review the parameters:
* `core-foundation` - name of the bridge you want to deploy. Unless deploying a custom bridge, you don't need to change this line
* `192.0.2.1` - replace with your node's IP address
* `ansible_user` - user to ssh into your node. Usually it's either `ubuntu` or `root`
* `ansible_python_interpreter` - path to python interpreter on your node. With Ubuntu 16.04 this should work with default value, however if running the playbook you get an error that `python3` is not found, try changing this to `/usr/bin/python`
* `signer_keyfile` - copy json content (`'{...}'`) of authority's keystore file
* `signer_password` - set this to authority's password
* `syslog_server_port` - set this to `server:port` of syslog server (should be provided to you)
If you're a new validator joining an existing bridge setup, you may want to additionally set the following parameters in `hosts.yml`:
* `last_checked_deposit_relay`
* `last_checked_withdraw_relay`
* `last_checked_withdraw_confirm`
If set, these values overwrite initial block numbers in `db.toml`, so that your node won't be re-processing transactions that are already processed by existing validators. You should get exact values from other validators before running the playbook.
### Installing the node
1. If ssh user can't execute `sudo` without password, you will need to add `--ask-become-pass` option below (without `[]` brackets) and provide sudo password when prompted by the playbook.
2. Run the playbook
```
ansible-playbook -i hosts.yml [--ask-become-pass] authority-node.yml
```
3. Playbook should complete without errors
## Setup details
To get more details about the setup, [go here](./DETAILS.md)
## Changes required for new bridges
To prepare configuration files for a newly deployed bridg, [go here](./NEW-BRIDGE.md)

@ -0,0 +1,2 @@
[ssh_connection]
pipelining = True

@ -0,0 +1,17 @@
---
- hosts: all
become: yes
gather_facts: no
# vars:
# home_signer_address: "0x{{ (signer_keyfile|from_json).address }}"
# home_signer_keyfile: '{{ signer_keyfile }}'
# home_signer_password: "{{ signer_password }}"
# foreign_signer_address: "{{ home_signer_address }}"
# foreign_signer_keyfile: '{{ home_signer_keyfile }}'
# foreign_signer_password: "{{ home_signer_password }}"
# bridge_home_password_file: "password.txt"
# bridge_foreign_password_file: "password.txt"
roles:
- backward-compatibility
- authority-preconf
- bridge

@ -0,0 +1,6 @@
### global settings
base_path: "/home/{{ service_user }}/poa-bridge"
become_method: sudo
service_user: bridgeuser

@ -0,0 +1,32 @@
### home side rpc
home_rpc_url: https://core.poa.network
home_rpc_port: 443
### foreign side rpc
foreign_rpc_url: https://mainnet.infura.io/metamask
foreign_rpc_port: 443
### bridge configs
bridge_deposit_relay_gas: 250000
bridge_withdraw_relay_gas: 300000
bridge_withdraw_confirm_gas: 300000
bridge_authorities_requires_signatures: 2
bridge_home_required_confirmations: 8
bridge_foreign_required_confirmations: 8
bridge_home_contract_address: "0xB87b6077D59B01Ab9fa8cd5A1A21D02a4d60D358"
bridge_foreign_contract_address: "0xd819E948b14cA6AAD2b7Ffd333cCDf732b129EeD"
bridge_home_contract_deploy: 2477327
bridge_foreign_contract_deploy: 5578725
bridge_home_poll_interval: 4
bridge_foreign_poll_interval: 10
bridge_home_default_gas_price: 1000000000
bridge_foreign_gas_price_oracle_url: https://gasprice.poa.network
bridge_foreign_gas_price_timeout: 10
bridge_foreign_gas_price_speed: fast #other possible values: slow, standard, instant
bridge_foreign_default_gas_price: 21000000000

@ -0,0 +1,25 @@
### home side rpc
home_rpc_url: https://sokol.poa.network
home_rpc_port: 443
### foreign side rpc
foreign_rpc_url: https://kovan.infura.io/mew
foreign_rpc_port: 443
### bridge configs
bridge_deposit_relay_gas: 3000000
bridge_withdraw_relay_gas: 3000000
bridge_withdraw_confirm_gas: 3000000
bridge_authorities_requires_signatures: 1
bridge_home_required_confirmations: 0
bridge_foreign_required_confirmations: 0
bridge_home_contract_address: "0x98f7b68C0Ef6A7DA0Bb0E786144A87bfEcc5cbD1"
bridge_foreign_contract_address: "0x5c29759020Fa2251B6481A3Ac1Ee507Ddbdc075c"
bridge_home_contract_deploy: 2213129
bridge_foreign_contract_deploy: 7066466
bridge_home_poll_interval: 4
bridge_foreign_poll_interval: 3

@ -0,0 +1,13 @@
---
core-foundation:
hosts:
192.0.2.1:
ansible_user: ubuntu
ansible_python_interpreter: "/usr/bin/python3"
signer_keyfile: ''
signer_password: ""
syslog_server_port: "" # this value should be provided to you
# last_checked_deposit_relay: 1 # optional value, consult README
# last_checked_withdraw_relay: 1 # optional value, consult README
# last_checked_withdraw_confirm: 1 # optional value, consult README

@ -0,0 +1,7 @@
###### Accepts the following parametrs:
#
# syslog_server_port server:port to forward syslog to (port is required, commonly port is 514)
#
---
syslog_server_port: ""
custom_ssh_port: ""

@ -0,0 +1,20 @@
---
- name: restart ufw
service:
name: ufw
state: restarted
- name: restart chrony
service:
name: chrony
state: restarted
- name: restart rsyslog
service:
name: rsyslog
state: restarted
- name: restart sshd
service:
name: sshd
state: restarted

@ -0,0 +1,5 @@
---
- name: Preconf.Create user
user:
name: "{{ service_user }}"
shell: "/bin/bash"

@ -0,0 +1,28 @@
---
- name: Check if remote computer is listening on standard ssh port
become: no
wait_for: port="{{ ansible_port | default(22) }}" state="started" host="{{ inventory_hostname }}" connect_timeout="3" timeout="4"
delegate_to: "localhost"
ignore_errors: "yes"
register: port_used
- name: Set inventory ansible_port to custom
set_fact: ansible_port="{{ custom_ssh_port }}"
when: port_used.state is undefined
- name: Preconf - setup UFW firewall
import_tasks: ufw.yml
- name: Preconf - sshd
import_tasks: sshd.yml
when: custom_ssh_port != "" and custom_ssh_port != ansible_port | default(22)
- name: Preconf - create user
import_tasks: create-user.yml
- name: Preconf - configure syslog forwarding
import_tasks: syslog-forward.yml
when: syslog_server_port != ""
- name: Preconf - run handlers immediately
meta: flush_handlers

@ -0,0 +1,33 @@
- name: Save old SSH port to variable
set_fact:
old_port: "{{ ansible_port | default(22) }}"
- name: Setup new SSH port
lineinfile:
dest: "/etc/ssh/sshd_config"
regexp: "^Port"
line: "Port {{ custom_ssh_port }}"
notify: restart sshd
- name: Preconf - run handlers immediately
meta: flush_handlers
- name: Doublecheck if computer is listening custom SSH port before removing old port access
become: no
wait_for: port="{{ custom_ssh_port }}" state="started" host="{{ inventory_hostname }}" connect_timeout="3" timeout="4"
delegate_to: "localhost"
register: port_used
- name: Preconf.UFW - remove default ssh access
ufw:
delete: yes
rule: "allow"
port: "{{ old_port }}"
proto: "tcp"
when: port_used is defined and old_port!=custom_ssh_port
notify:
- restart ufw
- name: Set inventory ansible_port to custom
set_fact: ansible_port="{{ custom_ssh_port }}"

@ -0,0 +1,27 @@
---
- name: Preconf.Syslog forward - apt install rsyslog-gnutls package
apt:
name: rsyslog-gnutls
state: present
update_cache: yes
- name: Preconf.Syslog forward - download papertrail CA
get_url:
url: "https://papertrailapp.com/tools/papertrail-bundle.pem"
checksum: "md5:ba3b40a34ec33ac0869fa5b17a0c80fc"
dest: "/etc/papertrail-bundle.pem"
mode: 0644
owner: root
group: root
notify:
- restart rsyslog
- name: Preconf.Syslog forward - create client config
template:
src: "rsyslog-tls-client.conf.j2"
dest: "/etc/rsyslog.d/tls-client.conf"
mode: 0644
owner: root
group: root
notify:
- restart rsyslog

@ -0,0 +1,47 @@
# to verify ufw configuration run:
# sudo ufw status verbose
---
- name: UFW
block:
- name: Preconf.UFW - install ufw
package:
name: ufw
state: present
- name: Preconf.UFW - clean old rules
ufw:
state: reset
- name: Preconf.UFW - configure defaults
ufw:
direction: "{{ item.direction }}"
policy: "{{ item.policy }}"
with_items:
- direction: "incoming"
policy: "deny"
- direction: "outgoing"
policy: "allow"
- name: Preconf.UFW - allow ssh access
ufw:
rule: "allow"
port: "{{ ansible_port | default(22) }}"
proto: "tcp"
- name: Preconf.UFW - allow custom port access
ufw:
rule: "allow"
port: "{{ custom_ssh_port }}"
proto: "tcp"
when: custom_ssh_port!="" and custom_ssh_port!=(ansible_port|default(22))
- name: Preconf.UFW - disable logging
ufw:
logging: off
- name: Preconf.UFW - enable ufw to start on boot
ufw:
state: enabled
notify:
- restart ufw

@ -0,0 +1,6 @@
$DefaultNetstreamDriverCAFile /etc/papertrail-bundle.pem
$ActionSendStreamDriver gtls
$ActionSendStreamDriverMode 1
$ActionSendStreamDriverAuthMode x509/name
$ActionSendStreamDriverPermittedPeer *.papertrailapp.com
*.* @@{{ syslog_server_port }}

@ -0,0 +1,15 @@
---
- name: BC - set home and foreign variables from signer
block:
- set_fact:
home_signer_address: "0x{{ (signer_keyfile|from_json).address }}"
home_signer_keyfile: '{{ signer_keyfile }}'
home_signer_password: "{{ signer_password }}"
- set_fact:
foreign_signer_address: "{{ home_signer_address }}"
foreign_signer_keyfile: '{{ home_signer_keyfile }}'
foreign_signer_password: "{{ home_signer_password }}"
- set_fact:
bridge_home_password_file: "password.txt"
bridge_foreign_password_file: "password.txt"
when: signer_keyfile|default("") != "" or signer_password|default("") != ""

@ -0,0 +1,64 @@
###### Accepts the following parametrs:
#
# bridge_path (*) path to the bridge folder (also used in templates)
# bridge_bin_url (*) url from which to download bridge binary
# bridge_bin_sha256 (*) sha256 checksum of the binary
# bridge_service_name (*) name to be used for bridge service
# bridge_deposit_relay_gas bridge config option (used only in templates)
# bridge_withdraw_relay_gas bridge config option (used only in templates)
# bridge_withdraw_confirm_gas bridge config option (used only in templates)
# bridge_home_required_confirmations bridge config option (used only in templates)
# bridge_home_poll_interval bridge config option (used only in templates)
# bridge_home_request_timeout bridge config option (used only in templates)
# bridge_foreign_required_confirmations bridge config option (used only in templates)
# bridge_foreign_poll_interval bridge config option (used only in templates)
# bridge_foreign_request_timeout bridge config option (used only in templates)
# db_toml_location path to bridge db.toml **on local machine**
# restart_delay_sec (*) delay in seconds between restarts of brige service. Set to 0 to omit this option (used only in templates)
# bridge_keystore_folder (*) folder to store keystore files
# bridge_home_password_file (*) name of the file with password
# bridge_foreign_password_file (*) name of the file with password
# home_rpc_url url of home-side rpc endpoint
# foreign_rpc_url url of foreign-sode rpc endpoint
# home_rpc_port port of home-side rpc endpoint
# foreign_rpc_port port of foreign-side rpc endpoint
#
---
bridge_path: "{{ base_path }}/bridge"
bridge_bin_url: "https://s3.amazonaws.com/poa-bridge-iterim/release-v0.3.0/bridge"
bridge_bin_sha256: "4cfbba6f00fe6bbbd002b71ab4610c4bca06931496ee18fdbfd124d823b88bcb"
bridge_service_name: "bridge"
db_toml_location: ""
home_rpc_port: 443
foreign_rpc_port: 443
restart_delay_sec: 2
bridge_keystore_folder: "keys"
bridge_home_password_file: "home-password.txt"
bridge_foreign_password_file: "foreign-password.txt"
# set to -1 to use bridge binary default values
bridge_home_request_timeout: 360
bridge_foreign_request_timeout: 360
bridge_authorities: []
# set to empty string to use default value
bridge_home_gas_price_oracle_url: ""
# set to -1 to use default value
bridge_home_gas_price_timeout: -1
# set to empty string to use default value
bridge_home_gas_price_speed: ""
# set to -1 to use default value
bridge_home_default_gas_price: -1
# set to empty string to use default value
bridge_foreign_gas_price_oracle_url: ""
# set to -1 to use default value
bridge_foreign_gas_price_timeout: -1
# set to empty string to use default value
bridge_foreign_gas_price_speed: ""
# set to -1 to use default value
bridge_foreign_default_gas_price: -1

@ -0,0 +1,5 @@
---
- name: "restart {{ bridge_service_name }}"
service:
name: "{{ bridge_service_name }}"
state: restarted

@ -0,0 +1,128 @@
---
- name: "Bridge - create bridge folder"
file:
path: "{{ bridge_path }}"
state: directory
mode: 0700
owner: "{{ service_user }}"
group: "{{ service_user }}"
- name: "Bridge - download bridge binary"
get_url:
url: "{{ bridge_bin_url }}"
checksum: "sha256:{{ bridge_bin_sha256 }}"
dest: "{{ bridge_path }}/bridge"
mode: "0700"
owner: "{{ service_user }}"
group: "{{ service_user }}"
notify:
- restart {{ bridge_service_name }}
- name: "Bridge - create keystore folder"
file:
path: "{{ bridge_path }}/{{ bridge_keystore_folder }}"
state: directory
mode: 0700
owner: "{{ service_user }}"
group: "{{ service_user }}"
# - name: "Bridge - create keystore files"
# template:
# src: "{{ item }}.j2"
# dest: "{{ bridge_path }}/{{ bridge_keystore_folder }}/{{ item }}"
# with_items:
# - foreign-keystore.json
# - home-keystore.json
# notify:
# - restart bridge
- name: "Bridge - create home keystore file"
template:
src: "home-keystore.json.j2"
dest: "{{ bridge_path }}/{{ bridge_keystore_folder }}/home-keystore.json"
mode: 0600
owner: "{{ service_user }}"
group: "{{ service_user }}"
notify:
- restart bridge
- name: "Bridge - create home password file"
template:
src: "home-password.txt.j2"
dest: "{{ bridge_path }}/{{ bridge_home_password_file }}"
mode: 0600
owner: "{{ service_user }}"
group: "{{ service_user }}"
notify:
- restart bridge
- name: "Bridge - create foreign keystore file"
template:
src: "foreign-keystore.json.j2"
dest: "{{ bridge_path }}/{{ bridge_keystore_folder }}/foreign-keystore.json"
mode: 0600
owner: "{{ service_user }}"
group: "{{ service_user }}"
notify:
- restart bridge
when: home_signer_address != foreign_signer_address
- name: "Bridge - create home password file"
template:
src: "foreign-password.txt.j2"
dest: "{{ bridge_path }}/{{ bridge_foreign_password_file }}"
mode: 0600
owner: "{{ service_user }}"
group: "{{ service_user }}"
notify:
- restart bridge
when: bridge_home_password_file != bridge_foreign_password_file
- name: "Bridge - create bridge config"
template:
src: config.toml.j2
dest: "{{ bridge_path }}/config.toml"
mode: 0600
owner: "{{ service_user }}"
group: "{{ service_user }}"
notify:
- restart bridge
- name: "Bridge - create db.toml file from template"
template:
src: "db.toml.j2"
dest: "{{ bridge_path }}/db.toml"
mode: 0600
owner: "{{ service_user }}"
group: "{{ service_user }}"
force: no
when: db_toml_location == ""
- name: "Bridge - copy db.toml file from local machine"
copy:
src: "{{ db_toml_location }}"
dest: "{{ bridge_path }}/db.toml"
force: no
owner: "{{ service_user }}"
group: "{{ service_user }}"
mode: 0600
when: db_toml_location != ""
- name: "Bridge - install bridge service"
template:
src: bridge.service.j2
dest: /etc/systemd/system/{{ bridge_service_name }}.service
owner: root
group: root
mode: 0644
notify:
- restart {{ bridge_service_name }}
- name: "Bridge - enable bridge service to start at boot"
command: "systemctl enable {{ bridge_service_name }}.service"
- name: "Bridge - ensure bridge service is running"
systemd:
name: "{{ bridge_service_name }}.service"
state: started
enabled: yes

@ -0,0 +1,17 @@
[Unit]
Description=bridge
After=network.target
[Service]
User={{ service_user }}
Group={{ service_user }}
WorkingDirectory={{ bridge_path }}
Environment=RUST_LOG=info
ExecStart={{ bridge_path }}/bridge --config {{ bridge_path }}/config.toml --database {{ bridge_path }}/db.toml
Restart=always
{% if restart_delay_sec > 0 %}
RestartSec={{ restart_delay_sec }}
{% endif %}
[Install]
WantedBy=multi-user.target

@ -0,0 +1,57 @@
keystore = "{{ bridge_keystore_folder }}"
[home]
account = "{{ home_signer_address }}"
required_confirmations = {{ bridge_home_required_confirmations }}
poll_interval = {{ bridge_home_poll_interval }}
{% if bridge_home_request_timeout > -1 %}
request_timeout = {{ bridge_home_request_timeout }}
{% endif %}
rpc_host = "{{ home_rpc_url }}"
rpc_port = {{ home_rpc_port }}
password = "{{ bridge_home_password_file }}"
{% if bridge_home_gas_price_oracle_url != "" %}
gas_price_oracle_url = "{{ bridge_home_gas_price_oracle_url }}"
{% if bridge_home_gas_price_timeout > -1 %}
gas_price_timeout = {{ bridge_home_gas_price_timeout }}
{% endif %}
{% if bridge_home_gas_price_speed != "" %}
gas_price_speed = "{{ bridge_home_gas_price_speed }}"
{% endif %}
{% endif %}
{% if bridge_home_default_gas_price > -1 %}
default_gas_price = {{ bridge_home_default_gas_price }}
{% endif %}
[foreign]
account = "{{ foreign_signer_address }}"
required_confirmations = {{ bridge_foreign_required_confirmations }}
poll_interval = {{ bridge_foreign_poll_interval }}
{% if bridge_foreign_request_timeout > -1 %}
request_timeout = {{ bridge_foreign_request_timeout }}
{% endif %}
rpc_host = "{{ foreign_rpc_url }}"
rpc_port = {{ foreign_rpc_port }}
password = "{{ bridge_foreign_password_file }}"
{% if bridge_foreign_gas_price_oracle_url != "" %}
gas_price_oracle_url = "{{ bridge_foreign_gas_price_oracle_url }}"
{% if bridge_foreign_gas_price_timeout > -1 %}
gas_price_timeout = {{ bridge_foreign_gas_price_timeout }}
{% endif %}
{% if bridge_foreign_gas_price_speed != "" %}
gas_price_speed = "{{ bridge_foreign_gas_price_speed }}"
{% endif %}
{% endif %}
{% if bridge_foreign_default_gas_price > -1 %}
default_gas_price = {{ bridge_foreign_default_gas_price }}
{% endif %}
[authorities]
required_signatures = {{ bridge_authorities_requires_signatures }}
[transactions]
deposit_relay = { gas = {{ bridge_deposit_relay_gas }} }
withdraw_relay = { gas = {{ bridge_withdraw_relay_gas }} }
withdraw_confirm = { gas = {{ bridge_withdraw_confirm_gas }} }

@ -0,0 +1,5 @@
home_contract_address = "{{ bridge_home_contract_address }}"
foreign_contract_address = "{{ bridge_foreign_contract_address }}"
checked_deposit_relay = {{ last_checked_deposit_relay|default(bridge_home_contract_deploy) }}
checked_withdraw_relay = {{ last_checked_withdraw_relay|default(bridge_foreign_contract_deploy) }}
checked_withdraw_confirm = {{ last_checked_withdraw_confirm|default(bridge_foreign_contract_deploy) }}

@ -0,0 +1 @@
{{ (signer_keyfile|default("") != "") | ternary(foreign_signer_keyfile|to_json, foreign_signer_keyfile) }}

@ -0,0 +1 @@
{{ foreign_signer_password }}

@ -0,0 +1 @@
{{ (signer_keyfile|default("") != "") | ternary(home_signer_keyfile|to_json, home_signer_keyfile) }}

@ -0,0 +1 @@
{{ home_signer_password }}