Support multiple bridges in one monitor (#262)
This commit is contained in:
parent
4de24efc01
commit
65dd131107
@ -69,3 +69,4 @@ MONITOR_VALIDATOR_HOME_TX_LIMIT | Average gas usage of a transaction sent by a v
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT | Average gas usage of a transaction sent by a validator, it is used to estimate the number of transaction that can be paid by the validator. | integer
|
||||
MONITOR_TX_NUMBER_THRESHOLD | If estimated number of transaction is equal to or below this value, the monitor will report that the validator has less funds than it is required. | integer
|
||||
MONITOR_PORT | The port for the Monitor. | integer
|
||||
MONITOR_BRIDGE_NAME | The name to be used in the url path for the bridge | string
|
||||
|
3
deployment-e2e/molecule/monitor/converge.yml
Normal file
3
deployment-e2e/molecule/monitor/converge.yml
Normal file
@ -0,0 +1,3 @@
|
||||
---
|
||||
- import_playbook: ../../../deployment/site.yml
|
||||
- import_playbook: ./run-checks.yml
|
@ -29,10 +29,11 @@ provisioner:
|
||||
r: ["bug"]
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../../../deployment/site.yml
|
||||
converge: ./converge.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
monitor-host:
|
||||
MONITOR_PORT: 3003
|
||||
syslog_server_port: "udp://127.0.0.1:514"
|
||||
verifier:
|
||||
name: testinfra
|
||||
|
7
deployment-e2e/molecule/monitor/run-checks.yml
Normal file
7
deployment-e2e/molecule/monitor/run-checks.yml
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
- name: Generate initial data for monitor
|
||||
hosts: monitor
|
||||
become: true
|
||||
tasks:
|
||||
- name: Run monitor checks
|
||||
shell: /bin/bash -c 'cd /home/poadocker/bridge/monitor/scripts; ./getBridgeStats.sh >cronWorker.out 2>cronWorker.err'
|
@ -34,14 +34,14 @@ def test_logging(host, filename):
|
||||
|
||||
def test_home_exists(host):
|
||||
assert host.run_test(
|
||||
'curl -s http://localhost:3003 | '
|
||||
'curl -s http://localhost:3003/bridge | '
|
||||
'grep -q -i "home"'
|
||||
)
|
||||
|
||||
|
||||
def test_foreign_exists(host):
|
||||
assert host.run_test(
|
||||
'curl -s http://localhost:3003 | '
|
||||
'curl -s http://localhost:3003/bridge | '
|
||||
'grep -q -i "foreign"'
|
||||
)
|
||||
|
||||
@ -49,6 +49,6 @@ def test_foreign_exists(host):
|
||||
def test_no_error(host):
|
||||
assert host.run_expect(
|
||||
[1],
|
||||
'curl -s http://localhost:3003 | '
|
||||
'curl -s http://localhost:3003/bridge | '
|
||||
'grep -i -q "error"'
|
||||
)
|
||||
|
@ -79,6 +79,10 @@ Example config for installing only UI:
|
||||
`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.
|
||||
|
||||
## Examples
|
||||
|
||||
[Deploy a monitor for multiple bridges](./MONITOR.md)
|
||||
|
||||
## 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.
|
||||
|
104
deployment/MONITOR.md
Normal file
104
deployment/MONITOR.md
Normal file
@ -0,0 +1,104 @@
|
||||
## Deploy multiple bridge monitor on the same host
|
||||
|
||||
If you want to deploy a monitor for different bridges, the [monitor variables](../monitor/.env.example) should be configured in `group_vars/<bridge_name>.yml` for each bridge.
|
||||
|
||||
For example, let's say we are going to deploy a monitor for xDai bridge and for WETC bridge.
|
||||
|
||||
#### Setup ansible configuration for xDai Bridge
|
||||
|
||||
First we create `hosts.yml` file to deploy the monitor for xdai bridge
|
||||
```yaml
|
||||
---
|
||||
xdai:
|
||||
children:
|
||||
monitor:
|
||||
hosts:
|
||||
<host_ip_A>:
|
||||
ansible_user: ubuntu
|
||||
```
|
||||
In `group_vars/xdai.yml`
|
||||
```
|
||||
---
|
||||
MONITOR_BRIDGE_NAME: "xdai"
|
||||
MONITOR_PORT: 3003
|
||||
|
||||
COMMON_HOME_RPC_URL: "https://dai.poa.network"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
|
||||
COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io/v3/INFURA_KEY"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016"
|
||||
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK: 0
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
MONITOR_HOME_START_BLOCK: 759
|
||||
MONITOR_FOREIGN_START_BLOCK: 6478417
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 0
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
```
|
||||
|
||||
Run the playbook to deploy the monitor for xdai bridge
|
||||
```
|
||||
ansible-playbook -i hosts.yml site.yml
|
||||
```
|
||||
|
||||
This command will deploy the monitor component and enable statistics for xdai bridge.
|
||||
|
||||
#### Setup ansible configuration for WETC Bridge
|
||||
|
||||
Update `hosts.yml` file to deploy the monitor for WETC Bridge
|
||||
```yaml
|
||||
---
|
||||
wetc:
|
||||
children:
|
||||
monitor:
|
||||
hosts:
|
||||
<host_ip_A>:
|
||||
ansible_user: ubuntu
|
||||
```
|
||||
|
||||
In `group_vars/wetc.yml`
|
||||
```
|
||||
---
|
||||
MONITOR_BRIDGE_NAME: "wetc"
|
||||
|
||||
COMMON_HOME_RPC_URL: "https://ethereumclassic.network"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"
|
||||
COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io/v3/32e8e252699a4ac1b5dd5c1ef53cc301"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x0cB781EE62F815bdD9CD4c2210aE8600d43e7040"
|
||||
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice-etc.poa.network/"
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK: 15000000000
|
||||
COMMON_HOME_GAS_PRICE_FACTOR: 1
|
||||
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
MONITOR_HOME_START_BLOCK: 7703292
|
||||
MONITOR_FOREIGN_START_BLOCK: 7412459
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
```
|
||||
Given that there is a monitor component deployed in the system, the `MONITOR_PORT` variable is not needed.
|
||||
|
||||
Run the playbook to deploy the monitor for WETC Bridge
|
||||
```
|
||||
ansible-playbook -i hosts.yml site.yml
|
||||
```
|
||||
|
||||
They playbook will detect that the monitor component is already deployed in the system, so it will only generate the configuration needed to enable the WETC Bridge statistics.
|
||||
|
||||
##### Get Monitor results
|
||||
The monitor output will be available at `http://host_ip_A:MONITOR_PORT/MONITOR_BRIDGE_NAME`.
|
||||
|
||||
Given that in `xdai.env` the variable `MONITOR_BRIDGE_NAME` is set to `xdai`, the results are in the url `http://host_ip_A:3003/xdai/`.
|
||||
|
||||
Similar to the xdai case, in `wetc.env` the variable `MONITOR_BRIDGE_NAME` is set to `wetc`, so the results are in the url `http://host_ip_A:3003/wetc/`.
|
@ -42,6 +42,7 @@ UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "xdai"
|
||||
MONITOR_PORT: 3003
|
||||
MONITOR_HOME_START_BLOCK: 759
|
||||
MONITOR_FOREIGN_START_BLOCK: 6478417
|
||||
|
@ -44,9 +44,10 @@ UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "bridge"
|
||||
MONITOR_PORT: 3003
|
||||
MONITOR_HOME_START_BLOCK: 0
|
||||
MONITOR_FOREIGN_START_BLOCK: 0
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_LEFT_TX_THRESHOLD: 100
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
|
@ -41,9 +41,10 @@ UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
#montior
|
||||
#monitor
|
||||
MONITOR_BRIDGE_NAME: "bridge"
|
||||
MONITOR_HOME_START_BLOCK: 0
|
||||
MONITOR_FOREIGN_START_BLOCK: 0
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_LEFT_TX_THRESHOLD: 100
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
|
@ -43,6 +43,7 @@ UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "wetc"
|
||||
MONITOR_PORT: 3003
|
||||
MONITOR_HOME_START_BLOCK: 7703292
|
||||
MONITOR_FOREIGN_START_BLOCK: 7412459
|
||||
|
@ -1,4 +1,21 @@
|
||||
---
|
||||
- include_tasks: dependencies.yml
|
||||
- include_tasks: repo.yml
|
||||
- include_tasks: logging.yml
|
||||
- name: Check if component is already deployed
|
||||
shell: "test -f {{ bridge_path }}/{{ component }}/docker-compose.yml && echo 'true'"
|
||||
ignore_errors: True
|
||||
register: already_deployed
|
||||
when: check_deployed is defined
|
||||
|
||||
- name: Set if tasks should be skipped
|
||||
set_fact: skip_task="{{ already_deployed.stdout | default('false') }}"
|
||||
|
||||
- name: Include dependencies tasks
|
||||
include_tasks: dependencies.yml
|
||||
when: skip_task != true
|
||||
|
||||
- name: Include repo tasks
|
||||
include_tasks: repo.yml
|
||||
when: skip_task != true
|
||||
|
||||
- name: Include logging tasks
|
||||
include_tasks: logging.yml
|
||||
when: skip_task != true
|
||||
|
@ -1,3 +1,3 @@
|
||||
---
|
||||
dependencies:
|
||||
- role: common
|
||||
- { role: common, check_deployed: true, component: 'monitor' }
|
||||
|
@ -6,7 +6,7 @@
|
||||
day: "{{ monitor_cron_schedule.split(' ')[2] }}"
|
||||
month: "{{ monitor_cron_schedule.split(' ')[3] }}"
|
||||
weekday: "{{ monitor_cron_schedule.split(' ')[4] }}"
|
||||
job: "/bin/bash -c 'cd {{ bridge_path }}/monitor/scripts; ./checkDocker.sh >cronWorker.out 2>cronWorker.err'"
|
||||
job: "/bin/bash -c 'cd {{ bridge_path }}/monitor/scripts; ./getBridgeStats.sh >cronWorker.out 2>cronWorker.err'"
|
||||
- name: Add cron entry
|
||||
cron:
|
||||
name: "RUN_MONITOR_CHECKS"
|
||||
|
@ -1,6 +1,18 @@
|
||||
---
|
||||
- include_tasks: pre_config.yml
|
||||
- include_tasks: logging.yml
|
||||
- include_tasks: jumpbox.yml
|
||||
- include_tasks: servinstall.yml
|
||||
- include_tasks: cron.yml
|
||||
|
||||
- name: Include logging tasks
|
||||
include_tasks: logging.yml
|
||||
when: skip_task != true
|
||||
|
||||
- name: Include jumpbox tasks
|
||||
include_tasks: jumpbox.yml
|
||||
when: skip_task != true
|
||||
|
||||
- name: Include servinstall tasks
|
||||
include_tasks: servinstall.yml
|
||||
when: skip_task != true
|
||||
|
||||
- name: Include cron tasks
|
||||
include_tasks: cron.yml
|
||||
when: skip_task != true
|
||||
|
@ -3,3 +3,9 @@
|
||||
template:
|
||||
src: .env.j2
|
||||
dest: "{{ bridge_path }}/monitor/.env"
|
||||
when: skip_task != true
|
||||
|
||||
- name: Install bridge config env
|
||||
template:
|
||||
src: config.env.j2
|
||||
dest: "{{ bridge_path }}/monitor/configs/{{ MONITOR_BRIDGE_NAME }}.env"
|
||||
|
@ -1,24 +1 @@
|
||||
COMMON_HOME_RPC_URL={{ COMMON_HOME_RPC_URL }}
|
||||
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
|
||||
COMMON_HOME_BRIDGE_ADDRESS={{ COMMON_HOME_BRIDGE_ADDRESS }}
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
|
||||
MONITOR_HOME_START_BLOCK={{ MONITOR_HOME_START_BLOCK }}
|
||||
MONITOR_FOREIGN_START_BLOCK={{ MONITOR_FOREIGN_START_BLOCK }}
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT={{ MONITOR_VALIDATOR_HOME_TX_LIMIT }}
|
||||
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
|
||||
{% endif %}
|
||||
{% if COMMON_HOME_GAS_PRICE_SPEED_TYPE | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE={{ COMMON_HOME_GAS_PRICE_SPEED_TYPE }}
|
||||
{% endif %}
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK={{ COMMON_HOME_GAS_PRICE_FALLBACK }}
|
||||
{% if COMMON_HOME_GAS_PRICE_FACTOR | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_FACTOR={{ COMMON_HOME_GAS_PRICE_FACTOR }}
|
||||
{% endif %}
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT={{ MONITOR_VALIDATOR_FOREIGN_TX_LIMIT }}
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL={{ COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL }}
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE={{ COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE }}
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK={{ COMMON_FOREIGN_GAS_PRICE_FALLBACK }}
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
|
||||
MONITOR_LEFT_TX_THRESHOLD={{ MONITOR_LEFT_TX_THRESHOLD }}
|
||||
MONITOR_PORT={{ MONITOR_PORT }}
|
||||
|
34
deployment/roles/monitor/templates/config.env.j2
Normal file
34
deployment/roles/monitor/templates/config.env.j2
Normal file
@ -0,0 +1,34 @@
|
||||
MONITOR_BRIDGE_NAME={{ MONITOR_BRIDGE_NAME }}
|
||||
|
||||
COMMON_HOME_RPC_URL={{ COMMON_HOME_RPC_URL }}
|
||||
COMMON_HOME_BRIDGE_ADDRESS={{ COMMON_HOME_BRIDGE_ADDRESS }}
|
||||
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
|
||||
|
||||
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
|
||||
{% endif %}
|
||||
{% if COMMON_HOME_GAS_PRICE_SPEED_TYPE | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE={{ COMMON_HOME_GAS_PRICE_SPEED_TYPE }}
|
||||
{% endif %}
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK={{ COMMON_HOME_GAS_PRICE_FALLBACK }}
|
||||
{% if COMMON_HOME_GAS_PRICE_FACTOR | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_FACTOR={{ COMMON_HOME_GAS_PRICE_FACTOR }}
|
||||
{% endif %}
|
||||
|
||||
{% if COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL={{ COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL }}
|
||||
{% endif %}
|
||||
{% if COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE | default('') != '' %}
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE={{ COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE }}
|
||||
{% endif %}
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK={{ COMMON_FOREIGN_GAS_PRICE_FALLBACK }}
|
||||
{% if COMMON_FOREIGN_GAS_PRICE_FACTOR | default('') != '' %}
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
|
||||
{% endif %}
|
||||
|
||||
MONITOR_HOME_START_BLOCK={{ MONITOR_HOME_START_BLOCK }}
|
||||
MONITOR_FOREIGN_START_BLOCK={{ MONITOR_FOREIGN_START_BLOCK }}
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT={{ MONITOR_VALIDATOR_HOME_TX_LIMIT }}
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT={{ MONITOR_VALIDATOR_FOREIGN_TX_LIMIT }}
|
||||
MONITOR_TX_NUMBER_THRESHOLD={{ MONITOR_TX_NUMBER_THRESHOLD }}
|
@ -18,6 +18,7 @@ start(){
|
||||
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
|
||||
sudo -u "{{ compose_service_user }}" /bin/bash -c 'cd scripts; ./getBridgeStats.sh >cronWorker.out 2>cronWorker.err'
|
||||
}
|
||||
|
||||
stop(){
|
||||
|
@ -16,3 +16,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
MONITOR_TX_NUMBER_THRESHOLD=100
|
||||
MONITOR_PORT=3013
|
||||
MONITOR_BRIDGE_NAME=bridge
|
||||
|
@ -16,3 +16,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
MONITOR_TX_NUMBER_THRESHOLD=100
|
||||
MONITOR_PORT=3012
|
||||
MONITOR_BRIDGE_NAME=bridge
|
||||
|
@ -16,3 +16,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
MONITOR_TX_NUMBER_THRESHOLD=100
|
||||
MONITOR_PORT=3011
|
||||
MONITOR_BRIDGE_NAME=bridge
|
||||
|
@ -16,3 +16,4 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||
MONITOR_TX_NUMBER_THRESHOLD=100
|
||||
MONITOR_PORT=3010
|
||||
MONITOR_BRIDGE_NAME=bridge
|
||||
|
@ -20,7 +20,7 @@
|
||||
"foreign": "0x2B6871b9B02F73fa24F4864322CdC78604207769",
|
||||
"foreignToken": "0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B",
|
||||
"ui": "http://localhost:3000",
|
||||
"monitor": "http://monitor:3010"
|
||||
"monitor": "http://monitor:3010/bridge"
|
||||
},
|
||||
"ercToErcBridge": {
|
||||
"home": "0x1feB40aD9420b186F019A717c37f5546165d411E",
|
||||
@ -28,7 +28,7 @@
|
||||
"homeToken": "0x792455a6bCb62Ed4C4362D323E0590654CA4765c",
|
||||
"foreignToken": "0x3C665A31199694Bf723fD08844AD290207B5797f",
|
||||
"ui": "http://localhost:3001",
|
||||
"monitor": "http://monitor-erc20:3011"
|
||||
"monitor": "http://monitor-erc20:3011/bridge"
|
||||
},
|
||||
"ercToNativeBridge": {
|
||||
"home": "0x488Af810997eD1730cB3a3918cD83b3216E6eAda",
|
||||
@ -37,14 +37,14 @@
|
||||
"halfDuplexToken": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359",
|
||||
"saiTop": "0x9b0ccf7C8994E19F39b2B4CF708e0A7DF65fA8a3",
|
||||
"ui": "http://localhost:3002",
|
||||
"monitor": "http://monitor-erc20-native:3012"
|
||||
"monitor": "http://monitor-erc20-native:3012/bridge"
|
||||
},
|
||||
"amb": {
|
||||
"home": "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0",
|
||||
"foreign": "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0",
|
||||
"homeBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
||||
"foreignBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1",
|
||||
"monitor": "http://monitor-amb:3013"
|
||||
"monitor": "http://monitor-amb:3013/bridge"
|
||||
},
|
||||
"homeRPC": {
|
||||
"URL": "http://parity1:8545",
|
||||
|
@ -1,7 +1,7 @@
|
||||
const Web3 = require('web3')
|
||||
const { ERC677_BRIDGE_TOKEN_ABI, BRIDGE_VALIDATORS_ABI, FOREIGN_NATIVE_TO_ERC_ABI, BOX_ABI } = require('../commons')
|
||||
|
||||
const waitUntil = async (predicate, step = 100, timeout = 10000) => {
|
||||
const waitUntil = async (predicate, step = 100, timeout = 20000) => {
|
||||
const stopTime = Date.now() + timeout
|
||||
while (Date.now() <= stopTime) {
|
||||
const result = await predicate()
|
||||
|
@ -3,7 +3,7 @@ FILES=(getBalances.json validators.json eventsStats.json alerts.json)
|
||||
check_files_exist() {
|
||||
rc=0
|
||||
for f in "${FILES[@]}"; do
|
||||
command="test -f responses/$f"
|
||||
command="test -f responses/bridge/$f"
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec monitor /bin/bash -c "$command") || rc=1
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20 /bin/bash -c "$command") || rc=1
|
||||
(docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20-native /bin/bash -c "$command") || rc=1
|
||||
|
@ -1,3 +1,5 @@
|
||||
MONITOR_BRIDGE_NAME=bridge
|
||||
|
||||
COMMON_HOME_RPC_URL=https://sokol.poa.network
|
||||
COMMON_FOREIGN_RPC_URL=https://kovan.infura.io/mew
|
||||
COMMON_HOME_BRIDGE_ADDRESS=0xABb4C1399DcC28FBa3Beb76CAE2b50Be3e087353
|
||||
|
@ -126,7 +126,7 @@ Using Docker:
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
- The application will run on `http://localhost:PORT`, where `PORT` is specified in your `.env` file.
|
||||
- The application will run on `http://localhost:MONITOR_PORT/MONITOR_BRIDGE_NAME`, where `MONITOR_PORT` and `MONITOR_BRIDGE_NAME` are specified in your `.env` file.
|
||||
- To enabled debug logging, set `DEBUG=1` variable in `.env`.
|
||||
|
||||
## Check balances of contracts and validators, get unprocessed events
|
||||
|
@ -1,13 +1,17 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const Web3 = require('web3')
|
||||
const logger = require('./logger')('checkWorker')
|
||||
const { getBridgeMode } = require('../commons')
|
||||
const getBalances = require('./getBalances')
|
||||
const getShortEventStats = require('./getShortEventStats')
|
||||
const validators = require('./validators')
|
||||
const { writeFile, createDir } = require('./utils/file')
|
||||
|
||||
const { COMMON_HOME_BRIDGE_ADDRESS, COMMON_HOME_RPC_URL, MONITOR_BRIDGE_NAME } = process.env
|
||||
|
||||
const MONITOR_VALIDATOR_HOME_TX_LIMIT = Number(process.env.MONITOR_VALIDATOR_HOME_TX_LIMIT) || 0
|
||||
const MONITOR_VALIDATOR_FOREIGN_TX_LIMIT = Number(process.env.MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) || 0
|
||||
const MONITOR_TX_NUMBER_THRESHOLD = Number(process.env.MONITOR_TX_NUMBER_THRESHOLD) || 100
|
||||
|
||||
const { COMMON_HOME_BRIDGE_ADDRESS, COMMON_HOME_RPC_URL } = process.env
|
||||
const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL)
|
||||
const web3Home = new Web3(homeProvider)
|
||||
|
||||
@ -15,6 +19,7 @@ const { HOME_ERC_TO_ERC_ABI } = require('../commons')
|
||||
|
||||
async function checkWorker() {
|
||||
try {
|
||||
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
||||
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||
const bridgeMode = await getBridgeMode(homeBridge)
|
||||
logger.debug('Bridge mode:', bridgeMode)
|
||||
@ -26,12 +31,35 @@ async function checkWorker() {
|
||||
const foreign = Object.assign({}, balances.foreign, events.foreign)
|
||||
const status = Object.assign({}, balances, events, { home }, { foreign })
|
||||
if (!status) throw new Error('status is empty: ' + JSON.stringify(status))
|
||||
fs.writeFileSync(path.join(__dirname, '/responses/getBalances.json'), JSON.stringify(status, null, 4))
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/getBalances.json`, status)
|
||||
|
||||
logger.debug('calling validators()')
|
||||
const vBalances = await validators(bridgeMode)
|
||||
if (!vBalances) throw new Error('vBalances is empty: ' + JSON.stringify(vBalances))
|
||||
fs.writeFileSync(path.join(__dirname, '/responses/validators.json'), JSON.stringify(vBalances, null, 4))
|
||||
|
||||
vBalances.homeOk = true
|
||||
vBalances.foreignOk = true
|
||||
|
||||
if (MONITOR_VALIDATOR_HOME_TX_LIMIT) {
|
||||
for (const hv in vBalances.home.validators) {
|
||||
if (vBalances.home.validators[hv].leftTx < MONITOR_TX_NUMBER_THRESHOLD) {
|
||||
vBalances.homeOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
|
||||
for (const hv in vBalances.foreign.validators) {
|
||||
if (vBalances.foreign.validators[hv].leftTx < MONITOR_TX_NUMBER_THRESHOLD) {
|
||||
vBalances.foreignOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vBalances.ok = vBalances.homeOk && vBalances.foreignOk
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/validators.json`, vBalances)
|
||||
logger.debug('Done')
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
|
@ -1,19 +1,28 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const logger = require('./logger')('checkWorker2')
|
||||
const eventsStats = require('./eventsStats')
|
||||
const alerts = require('./alerts')
|
||||
const { writeFile, createDir } = require('./utils/file')
|
||||
|
||||
const { MONITOR_BRIDGE_NAME } = process.env
|
||||
|
||||
async function checkWorker2() {
|
||||
try {
|
||||
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
||||
logger.debug('calling eventsStats()')
|
||||
const evStats = await eventsStats()
|
||||
if (!evStats) throw new Error('evStats is empty: ' + JSON.stringify(evStats))
|
||||
fs.writeFileSync(path.join(__dirname, '/responses/eventsStats.json'), JSON.stringify(evStats, null, 4))
|
||||
evStats.ok =
|
||||
(evStats.onlyInHomeDeposits || evStats.home.deliveredMsgNotProcessedInForeign).length === 0 &&
|
||||
(evStats.onlyInForeignDeposits || evStats.home.processedMsgNotDeliveredInForeign).length === 0 &&
|
||||
(evStats.onlyInHomeWithdrawals || evStats.foreign.deliveredMsgNotProcessedInHome).length === 0 &&
|
||||
(evStats.onlyInForeignWithdrawals || evStats.foreign.processedMsgNotDeliveredInHome).length === 0
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/eventsStats.json`, evStats)
|
||||
|
||||
logger.debug('calling alerts()')
|
||||
const _alerts = await alerts()
|
||||
if (!_alerts) throw new Error('alerts is empty: ' + JSON.stringify(_alerts))
|
||||
fs.writeFileSync(path.join(__dirname, '/responses/alerts.json'), JSON.stringify(_alerts, null, 4))
|
||||
_alerts.ok = !_alerts.executeAffirmations.mostRecentTxHash && !_alerts.executeSignatures.mostRecentTxHash
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/alerts.json`, _alerts)
|
||||
logger.debug('Done x2')
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
|
@ -1,15 +1,18 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const logger = require('./logger')('checkWorker3')
|
||||
const stuckTransfers = require('./stuckTransfers')
|
||||
const { writeFile, createDir } = require('./utils/file')
|
||||
|
||||
const { MONITOR_BRIDGE_NAME } = process.env
|
||||
|
||||
async function checkWorker3() {
|
||||
try {
|
||||
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
||||
logger.debug('calling stuckTransfers()')
|
||||
const transfers = await stuckTransfers()
|
||||
// console.log(transfers)
|
||||
if (!transfers) throw new Error('transfers is empty: ' + JSON.stringify(transfers))
|
||||
fs.writeFileSync(path.join(__dirname, '/responses/stuckTransfers.json'), JSON.stringify(transfers, null, 4))
|
||||
transfers.ok = transfers.total.length === 0
|
||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/stuckTransfers.json`, transfers)
|
||||
logger.debug('Done')
|
||||
} catch (e) {
|
||||
logger.error('checkWorker3.js', e)
|
||||
|
0
monitor/configs/.gitkeep
Normal file
0
monitor/configs/.gitkeep
Normal file
@ -10,5 +10,7 @@ services:
|
||||
env_file: ./.env
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
volumes:
|
||||
- ./responses:/mono/monitor/responses
|
||||
restart: unless-stopped
|
||||
entrypoint: "yarn check-and-start"
|
||||
entrypoint: "yarn start"
|
||||
|
@ -1,47 +1,15 @@
|
||||
require('dotenv').config()
|
||||
const express = require('express')
|
||||
const fs = require('fs')
|
||||
const { isV1Bridge } = require('./utils/serverUtils')
|
||||
const { readFile } = require('./utils/file')
|
||||
|
||||
const app = express()
|
||||
const bridgeRouter = express.Router({ mergeParams: true })
|
||||
|
||||
const MONITOR_VALIDATOR_HOME_TX_LIMIT = Number(process.env.MONITOR_VALIDATOR_HOME_TX_LIMIT) || 0
|
||||
const MONITOR_VALIDATOR_FOREIGN_TX_LIMIT = Number(process.env.MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) || 0
|
||||
const MONITOR_TX_NUMBER_THRESHOLD = Number(process.env.MONITOR_TX_NUMBER_THRESHOLD) || 100
|
||||
console.log('MONITOR_TX_NUMBER_THRESHOLD = ' + MONITOR_TX_NUMBER_THRESHOLD)
|
||||
app.use('/:bridgeName', bridgeRouter)
|
||||
|
||||
async function readFile(path) {
|
||||
bridgeRouter.get('/', async (req, res, next) => {
|
||||
try {
|
||||
const content = await fs.readFileSync(path)
|
||||
const json = JSON.parse(content)
|
||||
const timeDiff = Math.floor(Date.now() / 1000) - json.lastChecked
|
||||
return Object.assign({}, json, { timeDiff })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return {
|
||||
error: 'please check your worker'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function initV1routes(app) {
|
||||
const exposeV1Routes = await isV1Bridge()
|
||||
if (exposeV1Routes) {
|
||||
app.get('/stuckTransfers', async (req, res, next) => {
|
||||
try {
|
||||
const results = await readFile('./responses/stuckTransfers.json')
|
||||
results.ok = results.total.length === 0
|
||||
res.json(results)
|
||||
} catch (e) {
|
||||
next(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
app.get('/', async (req, res, next) => {
|
||||
try {
|
||||
const results = await readFile('./responses/getBalances.json')
|
||||
const results = await readFile(`./responses/${req.params.bridgeName}/getBalances.json`)
|
||||
res.json(results)
|
||||
} catch (e) {
|
||||
// this will eventually be handled by your error handling middleware
|
||||
@ -49,31 +17,9 @@ app.get('/', async (req, res, next) => {
|
||||
}
|
||||
})
|
||||
|
||||
app.get('/validators', async (req, res, next) => {
|
||||
bridgeRouter.get('/validators', async (req, res, next) => {
|
||||
try {
|
||||
const results = await readFile('./responses/validators.json')
|
||||
results.homeOk = true
|
||||
results.foreignOk = true
|
||||
|
||||
if (MONITOR_VALIDATOR_HOME_TX_LIMIT) {
|
||||
for (const hv in results.home.validators) {
|
||||
if (results.home.validators[hv].leftTx < MONITOR_TX_NUMBER_THRESHOLD) {
|
||||
results.homeOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
|
||||
for (const hv in results.foreign.validators) {
|
||||
if (results.foreign.validators[hv].leftTx < MONITOR_TX_NUMBER_THRESHOLD) {
|
||||
results.foreignOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results.ok = results.homeOk && results.foreignOk
|
||||
const results = await readFile(`./responses/${req.params.bridgeName}/validators.json`)
|
||||
res.json(results)
|
||||
} catch (e) {
|
||||
// this will eventually be handled by your error handling middleware
|
||||
@ -81,15 +27,9 @@ app.get('/validators', async (req, res, next) => {
|
||||
}
|
||||
})
|
||||
|
||||
// responses/eventsStats.json
|
||||
app.get('/eventsStats', async (req, res, next) => {
|
||||
bridgeRouter.get('/eventsStats', async (req, res, next) => {
|
||||
try {
|
||||
const results = await readFile('./responses/eventsStats.json')
|
||||
results.ok =
|
||||
(results.onlyInHomeDeposits || results.home.deliveredMsgNotProcessedInForeign).length === 0 &&
|
||||
(results.onlyInForeignDeposits || results.home.processedMsgNotDeliveredInForeign).length === 0 &&
|
||||
(results.onlyInHomeWithdrawals || results.foreign.deliveredMsgNotProcessedInHome).length === 0 &&
|
||||
(results.onlyInForeignWithdrawals || results.foreign.processedMsgNotDeliveredInHome).length === 0
|
||||
const results = await readFile(`./responses/${req.params.bridgeName}/eventsStats.json`)
|
||||
res.json(results)
|
||||
} catch (e) {
|
||||
// this will eventually be handled by your error handling middleware
|
||||
@ -97,17 +37,23 @@ app.get('/eventsStats', async (req, res, next) => {
|
||||
}
|
||||
})
|
||||
|
||||
app.get('/alerts', async (req, res, next) => {
|
||||
bridgeRouter.get('/alerts', async (req, res, next) => {
|
||||
try {
|
||||
const results = await readFile('./responses/alerts.json')
|
||||
results.ok = !results.executeAffirmations.mostRecentTxHash && !results.executeSignatures.mostRecentTxHash
|
||||
const results = await readFile(`./responses/${req.params.bridgeName}/alerts.json`)
|
||||
res.json(results)
|
||||
} catch (e) {
|
||||
next(e)
|
||||
}
|
||||
})
|
||||
|
||||
initV1routes(app)
|
||||
bridgeRouter.get('/stuckTransfers', async (req, res, next) => {
|
||||
try {
|
||||
const results = await readFile(`./responses/${req.params.bridgeName}/stuckTransfers.json`)
|
||||
res.json(results)
|
||||
} catch (e) {
|
||||
next(e)
|
||||
}
|
||||
})
|
||||
|
||||
const port = process.env.MONITOR_PORT || 3003
|
||||
app.set('port', port)
|
||||
|
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
cd $(dirname $0)/..
|
||||
|
||||
if /usr/local/bin/docker-compose ps | grep -q -i 'monitor'; then
|
||||
# https://github.com/docker/compose/issues/3352
|
||||
COMPOSE_INTERACTIVE_NO_CLI=1 /usr/local/bin/docker-compose exec -T monitor /bin/bash -c 'yarn check-all'
|
||||
else
|
||||
echo "Monitor is not running, skipping checks."
|
||||
fi
|
11
monitor/scripts/getBridgeStats.sh
Executable file
11
monitor/scripts/getBridgeStats.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
cd $(dirname $0)/..
|
||||
|
||||
if /usr/local/bin/docker-compose ps | grep -q -i 'monitor'; then
|
||||
for file in configs/*.env
|
||||
do
|
||||
docker run --rm --env-file $file -v $(pwd)/responses:/mono/monitor/responses monitor_monitor /bin/bash -c 'yarn check-all'
|
||||
done
|
||||
else
|
||||
echo "Monitor is not running, skipping checks."
|
||||
fi
|
36
monitor/utils/file.js
Normal file
36
monitor/utils/file.js
Normal file
@ -0,0 +1,36 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
async function readFile(filePath) {
|
||||
try {
|
||||
const content = await fs.readFileSync(filePath)
|
||||
const json = JSON.parse(content)
|
||||
const timeDiff = Math.floor(Date.now() / 1000) - json.lastChecked
|
||||
return Object.assign({}, json, { timeDiff })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return {
|
||||
error: 'the bridge statistics are not available'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeFile(filePath, object) {
|
||||
fs.writeFileSync(path.join(process.cwd(), filePath), JSON.stringify(object, null, 4))
|
||||
}
|
||||
|
||||
function createDir(dirPath) {
|
||||
try {
|
||||
fs.mkdirSync(path.join(process.cwd(), dirPath), { recursive: true })
|
||||
} catch (e) {
|
||||
if (!e.message.includes('exists')) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
readFile,
|
||||
writeFile,
|
||||
createDir
|
||||
}
|
Loading…
Reference in New Issue
Block a user