diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 35708b897..a275d9431 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -53,6 +53,8 @@ ORACLE_SHUTDOWN_CONTRACT_METHOD | Method signature to be used in the side chain ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Foreign chain. Infinite, if not provided. | `integer` ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Home chain. Infinite, if not provided. | `integer` ORACLE_JSONRPC_ERROR_CODES | Override default JSON rpc error codes that can trigger RPC fallback to the next URL from the list (or a retry in case of a single RPC URL). Default is `-32603,-32002,-32005`. Should be a comma-separated list of negative integers. | `string` +ORACLE_VALIDATOR_KEYSTORE_PATH | Path to the keystore v3 json file with the encrypted validator key. | `string` +ORACLE_VALIDATOR_KEYSTORE_PASSWORD | Password from the provided keystore file, oracle won't startup properly, if the provided password is invalid | `string` ## Monitor configuration diff --git a/deployment-e2e/Dockerfile b/deployment-e2e/Dockerfile index c7cf44068..bb7981672 100644 --- a/deployment-e2e/Dockerfile +++ b/deployment-e2e/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.7-stretch +FROM python:3.7 RUN curl -fsSL https://get.docker.com | sh -RUN pip3 install docker molecule==2.22rc1 molecule[docker] flake8 +RUN pip3 install docker molecule[docker,ansible] pytest pytest-testinfra flake8 WORKDIR mono/deployment-e2e diff --git a/deployment-e2e/molecule/monitor/molecule.yml b/deployment-e2e/molecule/monitor/molecule.yml index 8b8542d0f..9163e9501 100644 --- a/deployment-e2e/molecule/monitor/molecule.yml +++ b/deployment-e2e/molecule/monitor/molecule.yml @@ -3,12 +3,6 @@ dependency: name: galaxy driver: name: docker -lint: - name: yamllint - enabled: True - options: - config-data: - ignore: ../../hosts.yml platforms: - name: monitor-host groups: @@ -22,11 +16,6 @@ platforms: - /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: ./converge.yml @@ -37,14 +26,11 @@ provisioner: syslog_server_port: "udp://127.0.0.1:514" verifier: name: testinfra - lint: - name: flake8 additional_files_or_dirs: - ../../tests/* scenario: name: monitor test_sequence: - - lint - cleanup - destroy - dependency diff --git a/deployment-e2e/molecule/multiple/molecule.yml b/deployment-e2e/molecule/multiple/molecule.yml index 0f03732f2..050b706b6 100644 --- a/deployment-e2e/molecule/multiple/molecule.yml +++ b/deployment-e2e/molecule/multiple/molecule.yml @@ -3,12 +3,6 @@ dependency: name: galaxy driver: name: docker -lint: - name: yamllint - enabled: True - options: - config-data: - ignore: ../../hosts.yml platforms: - name: multiple-host groups: @@ -23,11 +17,6 @@ platforms: - /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: ../monitor/converge.yml @@ -39,14 +28,11 @@ provisioner: syslog_server_port: "udp://127.0.0.1:514" verifier: name: testinfra - lint: - name: flake8 additional_files_or_dirs: - ../../tests/* scenario: name: multiple test_sequence: - - lint - cleanup - destroy - dependency diff --git a/deployment-e2e/molecule/oracle/molecule.yml b/deployment-e2e/molecule/oracle/molecule.yml index e3ff47ecc..133e80172 100644 --- a/deployment-e2e/molecule/oracle/molecule.yml +++ b/deployment-e2e/molecule/oracle/molecule.yml @@ -3,18 +3,12 @@ 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 + - oracle_swarm image: ubuntu:16.04 privileged: true network_mode: host @@ -22,29 +16,22 @@ platforms: - /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: ../../../deployment/site.yml inventory: host_vars: oracle-host: - ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "6c48435bd464a53ed66ed62127c4dba8af75cf1a99a8ebe2680599948fbfbc6d" + ORACLE_VALIDATOR_KEYSTORE_PATH: "../../../e2e-commons/keystore.json" + ORACLE_VALIDATOR_KEYSTORE_PASSWORD: "12345678" syslog_server_port: "udp://127.0.0.1:514" verifier: name: testinfra - lint: - name: flake8 additional_files_or_dirs: - ../../tests/* scenario: name: oracle test_sequence: - - lint - cleanup - destroy - dependency diff --git a/deployment-e2e/molecule/oracle/tests/test_oracle.py b/deployment-e2e/molecule/oracle/tests/test_oracle.py index 147ff81a8..68ae3e9ef 100644 --- a/deployment-e2e/molecule/oracle/tests/test_oracle.py +++ b/deployment-e2e/molecule/oracle/tests/test_oracle.py @@ -3,22 +3,21 @@ import testinfra.utils.ansible_runner testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( - os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('oracle') + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('oracle_swarm') @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"), - ("oracle_bridge_shutdown_1"), + ("oracle_rabbit"), + ("oracle_redis"), + ("oracle_bridge_request"), + ("oracle_bridge_collected"), + ("oracle_bridge_affirmation"), + ("oracle_bridge_senderhome"), + ("oracle_bridge_senderforeign"), + ("oracle_bridge_shutdown"), ]) def test_docker_containers(host, name): - container = host.docker(name) - assert container.is_running + assert host.docker(name) is not None @pytest.mark.parametrize("service", [ diff --git a/deployment-e2e/molecule/ultimate-amb/molecule.yml b/deployment-e2e/molecule/ultimate-amb/molecule.yml index c523faf8c..a6bf6d093 100644 --- a/deployment-e2e/molecule/ultimate-amb/molecule.yml +++ b/deployment-e2e/molecule/ultimate-amb/molecule.yml @@ -25,8 +25,6 @@ provisioner: ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9" verifier: name: testinfra - lint: - name: flake8 scenario: name: ultimate-amb test_sequence: diff --git a/deployment-e2e/molecule/ultimate-erc-to-native/molecule.yml b/deployment-e2e/molecule/ultimate-erc-to-native/molecule.yml index 79084fc16..9ddb04481 100644 --- a/deployment-e2e/molecule/ultimate-erc-to-native/molecule.yml +++ b/deployment-e2e/molecule/ultimate-erc-to-native/molecule.yml @@ -27,8 +27,6 @@ provisioner: ORACLE_FOREIGN_START_BLOCK: 1 verifier: name: testinfra - lint: - name: flake8 scenario: name: ultimate-erc-to-native test_sequence: diff --git a/deployment/hosts.yml.example b/deployment/hosts.yml.example index 5cde8e82f..f02ac8cfc 100644 --- a/deployment/hosts.yml.example +++ b/deployment/hosts.yml.example @@ -7,6 +7,13 @@ sokol-kovan: ansible_user: ubuntu ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" #syslog_server_port: "udp://127.0.0.1:514" + oracle_swarm: + hosts: + 127.0.0.1: + ansible_user: ubuntu + ORACLE_VALIDATOR_KEYSTORE_PATH: "/path/to/keystore.json" + ORACLE_VALIDATOR_KEYSTORE_PASSWORD: "12345678" + #syslog_server_port: "udp://127.0.0.1:514" monitor: hosts: 127.0.0.1: diff --git a/deployment/requirements.txt b/deployment/requirements.txt deleted file mode 100644 index 81e83c69c..000000000 --- a/deployment/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -# pre-release because it contains "CI Fixes for ansible 2.8" -molecule==2.22rc1 -docker -flake8 diff --git a/deployment/roles/common/files/daemon.json b/deployment/roles/common/files/daemon.json index 5317bea81..27f789233 100644 --- a/deployment/roles/common/files/daemon.json +++ b/deployment/roles/common/files/daemon.json @@ -1,4 +1,4 @@ { - "live-restore": true, + "live-restore": false, "no-new-privileges": true } diff --git a/deployment/roles/common/tasks/dependencies.yml b/deployment/roles/common/tasks/dependencies.yml index 0c859c3d8..f7586866d 100644 --- a/deployment/roles/common/tasks/dependencies.yml +++ b/deployment/roles/common/tasks/dependencies.yml @@ -31,6 +31,7 @@ owner: "root" group: "root" mode: "0755" + when: skip_compose is undefined - name: Upgrade pip version shell: pip3 install --upgrade pip==19.3.1 @@ -45,6 +46,9 @@ group: docker createhome: yes +- name: reset ssh connection to allow user changes to affect ansible user + meta: reset_connection + - name: Install auditd apt: name: auditd diff --git a/deployment/roles/oracle_swarm/defaults/main.yml b/deployment/roles/oracle_swarm/defaults/main.yml new file mode 100644 index 000000000..1a6f85c31 --- /dev/null +++ b/deployment/roles/oracle_swarm/defaults/main.yml @@ -0,0 +1,9 @@ +--- +bridge_path: "/home/{{ compose_service_user }}/bridge" +bridge_data_path: "/home/{{ compose_service_user }}/bridge_data" +ORACLE_ALLOW_HTTP_FOR_RPC: no +ORACLE_QUEUE_URL: amqp://rabbit +ORACLE_REDIS_URL: redis://redis +keyfile_path: "/root/.key" +keystore_path: "/root/.keystore.json" +oracle_image: poanetwork/tokenbridge-oracle:latest diff --git a/deployment/roles/oracle_swarm/meta/main.yml b/deployment/roles/oracle_swarm/meta/main.yml new file mode 100644 index 000000000..00b677b86 --- /dev/null +++ b/deployment/roles/oracle_swarm/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - { role: common, skip_repo: true, skip_compose: true } diff --git a/deployment/roles/oracle_swarm/tasks/jumpbox.yml b/deployment/roles/oracle_swarm/tasks/jumpbox.yml new file mode 100644 index 000000000..35e086118 --- /dev/null +++ b/deployment/roles/oracle_swarm/tasks/jumpbox.yml @@ -0,0 +1,8 @@ +--- +- name: Pull the containers images + community.docker.docker_image: + name: "{{ oracle_image }}" + source: pull + when: skip_pull is undefined + vars: + ansible_python_interpreter: /usr/bin/python3 diff --git a/deployment/roles/oracle_swarm/tasks/logging.yml b/deployment/roles/oracle_swarm/tasks/logging.yml new file mode 100644 index 000000000..e54351998 --- /dev/null +++ b/deployment/roles/oracle_swarm/tasks/logging.yml @@ -0,0 +1,41 @@ +--- +- name: Set the oracle's containers local logs configuration file + template: + src: 31-oracle-docker.conf.j2 + dest: /etc/rsyslog.d/31-oracle-docker.conf + owner: root + group: root + mode: 0644 + +- name: Set the redis container local logs configuration file + template: + src: 32-redis-docker.conf.j2 + dest: /etc/rsyslog.d/32-redis-docker.conf + owner: root + group: root + mode: 0644 + +- name: Set the rabbit MQ container local logs configuration file + template: + src: 33-rabbit-docker.conf.j2 + dest: /etc/rsyslog.d/33-rabbit-docker.conf + owner: root + group: root + mode: 0644 + +- name: Set the log configuration file to send container logs to remote server + template: + src: 36-oracle-remote-logging.conf.j2 + dest: /etc/rsyslog.d/36-oracle-remote-logging.conf + owner: root + group: root + mode: 0644 + when: syslog_server_port is defined + +- 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, "ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY" ~' + notify: restart rsyslog diff --git a/deployment/roles/oracle_swarm/tasks/main.yml b/deployment/roles/oracle_swarm/tasks/main.yml new file mode 100644 index 000000000..16099ac27 --- /dev/null +++ b/deployment/roles/oracle_swarm/tasks/main.yml @@ -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 diff --git a/deployment/roles/oracle_swarm/tasks/post_config.yml b/deployment/roles/oracle_swarm/tasks/post_config.yml new file mode 100644 index 000000000..e67e31863 --- /dev/null +++ b/deployment/roles/oracle_swarm/tasks/post_config.yml @@ -0,0 +1,46 @@ +--- +- name: Get blocks + become_user: "{{ compose_service_user }}" + shell: docker run --env-file .env --rm {{ oracle_image }} scripts/getValidatorStartBlocks.js + args: + chdir: "{{ bridge_path }}/oracle" + register: BLOCKS + when: (ORACLE_HOME_START_BLOCK is not defined) or (ORACLE_FOREIGN_START_BLOCK is not defined) + +- name: Write blocks + blockinfile: + path: "{{ bridge_path }}/oracle/.env" + marker: "## {mark} Calculated by scripts/getValidatorStartBlocks.js" + block: | + ORACLE_HOME_START_BLOCK={{ (BLOCKS.stdout | from_json).homeStartBlock }} + ORACLE_FOREIGN_START_BLOCK={{ (BLOCKS.stdout | from_json).foreignStartBlock }} + when: (ORACLE_HOME_START_BLOCK is not defined) or (ORACLE_FOREIGN_START_BLOCK is not defined) + +- name: Copy keystore file + copy: + src: "{{ ORACLE_VALIDATOR_KEYSTORE_PATH }}" + dest: "{{ keystore_path }}" + owner: root + group: root + mode: 0600 + +- name: Create swarm secret + community.docker.docker_secret: + name: oracle_keystore + state: present + data_src: "{{ keystore_path }}" + vars: + ansible_python_interpreter: /usr/bin/python3 + +- name: Remove unencrypted keystore file + file: + path: "{{ keystore_path }}" + state: absent + +- name: Install .key config + template: + src: key.j2 + dest: "{{ keyfile_path }}" + owner: root + group: root + mode: 0600 diff --git a/deployment/roles/oracle_swarm/tasks/pre_config.yml b/deployment/roles/oracle_swarm/tasks/pre_config.yml new file mode 100644 index 000000000..03d7874b0 --- /dev/null +++ b/deployment/roles/oracle_swarm/tasks/pre_config.yml @@ -0,0 +1,47 @@ +--- +- name: Init docker swarm + community.docker.docker_swarm: + state: present + autolock_managers: yes + listen_addr: 127.0.0.1:2377 + vars: + ansible_python_interpreter: /usr/bin/python3 + +- name: Get unlock token + community.docker.docker_swarm_info: + unlock_key: yes + register: result + vars: + ansible_python_interpreter: /usr/bin/python3 + +- name: Print unlock token + debug: + var: result.swarm_unlock_key + +- name: Create oracle directory + file: + path: "{{ bridge_path }}/oracle" + state: directory + mode: '0755' + +- name: Create rabbitmq directory + file: + path: "{{ bridge_data_path }}/{{ item }}" + state: directory + mode: '0775' + loop: + - rabbitmq + - redis + +- name: Install .env config + template: + src: .env.j2 + dest: "{{ bridge_path }}/oracle/.env" + owner: "{{ compose_service_user }}" + mode: '0640' + +- name: Install docker-compose file + template: + src: docker-compose.yml.j2 + dest: "{{ bridge_path }}/oracle/docker-compose.yml" + mode: '0755' diff --git a/deployment/roles/oracle_swarm/tasks/servinstall.yml b/deployment/roles/oracle_swarm/tasks/servinstall.yml new file mode 100644 index 000000000..74ff01bf4 --- /dev/null +++ b/deployment/roles/oracle_swarm/tasks/servinstall.yml @@ -0,0 +1,19 @@ +# 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. +--- +- 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 diff --git a/deployment/roles/oracle_swarm/templates/.env.j2 b/deployment/roles/oracle_swarm/templates/.env.j2 new file mode 100644 index 000000000..575c05e03 --- /dev/null +++ b/deployment/roles/oracle_swarm/templates/.env.j2 @@ -0,0 +1,86 @@ +## General settings +ORACLE_BRIDGE_MODE={{ ORACLE_BRIDGE_MODE }} +{% if ORACLE_LOG_LEVEL | default('') != '' %} +ORACLE_LOG_LEVEL={{ ORACLE_LOG_LEVEL }} +{% endif %} + +## Home contract +COMMON_HOME_RPC_URL={{ COMMON_HOME_RPC_URL }} +COMMON_HOME_BRIDGE_ADDRESS={{ COMMON_HOME_BRIDGE_ADDRESS }} +ORACLE_HOME_RPC_POLLING_INTERVAL={{ ORACLE_HOME_RPC_POLLING_INTERVAL }} + +## Foreign contract +COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }} +{% if ORACLE_FOREIGN_ARCHIVE_RPC_URL | default('') != '' %} +ORACLE_FOREIGN_ARCHIVE_RPC_URL={{ ORACLE_FOREIGN_ARCHIVE_RPC_URL }} +{% endif %} +COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }} +ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }} + +{% if ORACLE_TX_REDUNDANCY | default('') != '' %} +ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }} +{% endif %} + +## Gasprice +{% 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 ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %} +ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL={{ ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL }} +{% endif %} +{% 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 ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %} +ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL={{ ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL }} +{% endif %} +{% if COMMON_FOREIGN_GAS_PRICE_FACTOR | default('') != '' %} +COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }} +{% endif %} + +## Transport configuration +ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }} +ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }} +ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }} +{% if ORACLE_FOREIGN_TX_RESEND_INTERVAL | default('') != '' %} +ORACLE_FOREIGN_TX_RESEND_INTERVAL={{ ORACLE_FOREIGN_TX_RESEND_INTERVAL }} +{% endif %} +{% if ORACLE_HOME_TX_RESEND_INTERVAL | default('') != '' %} +ORACLE_HOME_TX_RESEND_INTERVAL={{ ORACLE_HOME_TX_RESEND_INTERVAL }} +{% endif %} + +## Emergency shutdown configuration +{% if ORACLE_SHUTDOWN_SERVICE_URL | default('') != '' %} +ORACLE_SHUTDOWN_SERVICE_URL={{ ORACLE_SHUTDOWN_SERVICE_URL }} +{% endif %} +{% if ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | default('') != '' %} +ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL={{ ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL }} +{% endif %} +{% if ORACLE_SIDE_RPC_URL | default('') != '' %} +ORACLE_SIDE_RPC_URL={{ ORACLE_SIDE_RPC_URL }} +{% endif %} +{% if ORACLE_SHUTDOWN_CONTRACT_ADDRESS | default('') != '' %} +ORACLE_SHUTDOWN_CONTRACT_ADDRESS={{ ORACLE_SHUTDOWN_CONTRACT_ADDRESS }} +{% endif %} +{% if ORACLE_SHUTDOWN_CONTRACT_METHOD | default('') != '' %} +ORACLE_SHUTDOWN_CONTRACT_METHOD={{ ORACLE_SHUTDOWN_CONTRACT_METHOD }} +{% endif %} + +{% if ORACLE_HOME_START_BLOCK | default('') != '' %} +ORACLE_HOME_START_BLOCK={{ ORACLE_HOME_START_BLOCK }} +{% endif %} +{% if ORACLE_FOREIGN_START_BLOCK | default('') != '' %} +ORACLE_FOREIGN_START_BLOCK={{ ORACLE_FOREIGN_START_BLOCK }} +{% endif %} diff --git a/deployment/roles/oracle_swarm/templates/31-oracle-docker.conf.j2 b/deployment/roles/oracle_swarm/templates/31-oracle-docker.conf.j2 new file mode 100644 index 000000000..dc98ce57b --- /dev/null +++ b/deployment/roles/oracle_swarm/templates/31-oracle-docker.conf.j2 @@ -0,0 +1,11 @@ +$FileCreateMode 0644 +template(name="DockerLogFileName_Oracle" 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 'oracle_bridge_' then \ + ?DockerLogFileName_Oracle + +$FileCreateMode 0600 diff --git a/deployment/roles/oracle_swarm/templates/32-redis-docker.conf.j2 b/deployment/roles/oracle_swarm/templates/32-redis-docker.conf.j2 new file mode 100644 index 000000000..5a32db69e --- /dev/null +++ b/deployment/roles/oracle_swarm/templates/32-redis-docker.conf.j2 @@ -0,0 +1,11 @@ +$FileCreateMode 0644 +template(name="DockerLogFileName_Redis" type="list") { + constant(value="/var/log/docker/") + property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*redis.*)\\/[a-zA-Z0-9]+\\[") + constant(value="/docker.log") +} + +if $programname contains 'oracle' and $programname contains 'redis' then \ + ?DockerLogFileName_Redis + +$FileCreateMode 0600 diff --git a/deployment/roles/oracle_swarm/templates/33-rabbit-docker.conf.j2 b/deployment/roles/oracle_swarm/templates/33-rabbit-docker.conf.j2 new file mode 100644 index 000000000..0f0753d5a --- /dev/null +++ b/deployment/roles/oracle_swarm/templates/33-rabbit-docker.conf.j2 @@ -0,0 +1,11 @@ +$FileCreateMode 0644 +template(name="DockerLogFileName_Rabbit" type="list") { + constant(value="/var/log/docker/") + property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*rabbit.*)\\/[a-zA-Z0-9]+\\[") + constant(value="/docker.log") +} + +if $programname contains 'oracle' and $programname contains 'rabbit' then \ + ?DockerLogFileName_Rabbit + +$FileCreateMode 0600 diff --git a/deployment/roles/oracle_swarm/templates/36-oracle-remote-logging.conf.j2 b/deployment/roles/oracle_swarm/templates/36-oracle-remote-logging.conf.j2 new file mode 100644 index 000000000..f7bad3f33 --- /dev/null +++ b/deployment/roles/oracle_swarm/templates/36-oracle-remote-logging.conf.j2 @@ -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" + ) +} diff --git a/deployment/roles/oracle_swarm/templates/docker-compose.yml.j2 b/deployment/roles/oracle_swarm/templates/docker-compose.yml.j2 new file mode 100644 index 000000000..566c6a9ec --- /dev/null +++ b/deployment/roles/oracle_swarm/templates/docker-compose.yml.j2 @@ -0,0 +1,144 @@ +version: '3.9' +x-deploy: &x-deploy + resources: + limits: + cpus: '0.3' + memory: 500M + reservations: + memory: 100M +x-keystore-access: &x-keystore-access + environment: + ORACLE_VALIDATOR_KEYSTORE_PATH: /run/secrets/oracle_keystore + ORACLE_VALIDATOR_KEYSTORE_PASSWORD: + secrets: + - oracle_keystore +x-logging: &x-logging + driver: 'syslog' + options: {tag: '{{ '{{.Name}}/{{.ID}}' }}' } +services: + rabbit: + image: rabbitmq:3 + hostname: rabbit + deploy: *x-deploy + logging: *x-logging + environment: [ 'RABBITMQ_NODENAME=node@rabbit' ] + networks: + - net_rabbit_bridge_request + - net_rabbit_bridge_collected + - net_rabbit_bridge_affirmation + - net_rabbit_bridge_senderhome + - net_rabbit_bridge_senderforeign + volumes: [ '{{ bridge_data_path }}/rabbitmq:/var/lib/rabbitmq/mnesia' ] + redis: + image: redis:4 + hostname: redis + deploy: *x-deploy + logging: *x-logging + command: [ redis-server, --appendonly, 'yes' ] + networks: + - net_db_bridge_request + - net_db_bridge_collected + - net_db_bridge_affirmation + - net_db_bridge_senderhome + - net_db_bridge_senderforeign + - net_db_bridge_shutdown + volumes: [ '{{ bridge_data_path }}/redis:/data' ] + bridge_request: + image: {{ oracle_image }} + deploy: *x-deploy + logging: *x-logging + env_file: ./.env + <<: *x-keystore-access + entrypoint: yarn watcher:signature-request + networks: + - net_db_bridge_request + - net_rabbit_bridge_request + bridge_collected: + image: {{ oracle_image }} + deploy: *x-deploy + env_file: ./.env + entrypoint: yarn watcher:collected-signatures + networks: + - net_db_bridge_collected + - net_rabbit_bridge_collected + bridge_affirmation: + image: {{ oracle_image }} + deploy: *x-deploy + logging: *x-logging + env_file: ./.env + entrypoint: yarn watcher:affirmation-request + networks: + - net_db_bridge_affirmation + - net_rabbit_bridge_affirmation + bridge_senderhome: + image: {{ oracle_image }} + deploy: *x-deploy + env_file: ./.env + <<: *x-keystore-access + entrypoint: yarn sender:home + networks: + - net_db_bridge_senderhome + - net_rabbit_bridge_senderhome + bridge_senderforeign: + image: {{ oracle_image }} + deploy: *x-deploy + logging: *x-logging + env_file: ./.env + <<: *x-keystore-access + entrypoint: yarn sender:foreign + networks: + - net_db_bridge_senderforeign + - net_rabbit_bridge_senderforeign + bridge_shutdown: + image: {{ oracle_image }} + deploy: *x-deploy + env_file: ./.env + entrypoint: yarn manager:shutdown + networks: + - net_db_bridge_shutdown +{% if ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE" %} + bridge_transfer: + image: {{ oracle_image }} + deploy: *x-deploy + logging: *x-logging + env_file: ./.env + entrypoint: yarn watcher:transfer + networks: + - net_db_bridge_transfer + - net_rabbit_bridge_transfer +{% endif %} +{% if ORACLE_BRIDGE_MODE == "ARBITRARY_MESSAGE" %} + bridge_information: + image: {{ oracle_image }} + deploy: *x-deploy + logging: *x-logging + env_file: ./.env + entrypoint: yarn watcher:information-request + networks: + - net_db_bridge_information + - net_rabbit_bridge_information +{% endif %} +networks: + net_db_bridge_request: + net_db_bridge_collected: + net_db_bridge_affirmation: + net_db_bridge_senderhome: + net_db_bridge_senderforeign: + net_db_bridge_shutdown: +{% if ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE" %} + net_db_bridge_transfer: + net_rabbit_bridge_transfer: +{% endif %} +{% if ORACLE_BRIDGE_MODE == "ARBITRARY_MESSAGE" %} + net_db_bridge_information: + net_rabbit_bridge_information: +{% endif %} + net_rabbit_bridge_request: + net_rabbit_bridge_collected: + net_rabbit_bridge_affirmation: + net_rabbit_bridge_senderhome: + net_rabbit_bridge_senderforeign: + +secrets: + oracle_keystore: + external: true diff --git a/deployment/roles/oracle_swarm/templates/key.j2 b/deployment/roles/oracle_swarm/templates/key.j2 new file mode 100644 index 000000000..7b60fed2e --- /dev/null +++ b/deployment/roles/oracle_swarm/templates/key.j2 @@ -0,0 +1,2 @@ +## Validator-specific options +ORACLE_VALIDATOR_KEYSTORE_PASSWORD={{ ORACLE_VALIDATOR_KEYSTORE_PASSWORD }} diff --git a/deployment/roles/oracle_swarm/templates/poabridge.j2 b/deployment/roles/oracle_swarm/templates/poabridge.j2 new file mode 100644 index 000000000..b6c053fe7 --- /dev/null +++ b/deployment/roles/oracle_swarm/templates/poabridge.j2 @@ -0,0 +1,66 @@ +#! /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 + '/oracle' if bridge_path[:1] != "/" else bridge_path + '/oracle' }}" + +#Getting path to private key file and variable name for parsing key file +source {{ keyfile_path }} + +start(){ + echo "Starting bridge.." + cd $WORKDIR + sudo -u "{{ compose_service_user }}" docker stack rm oracle + sudo -u "{{ compose_service_user }}" "ORACLE_VALIDATOR_KEYSTORE_PASSWORD=$ORACLE_VALIDATOR_KEYSTORE_PASSWORD" docker stack deploy oracle -c docker-compose.yml +} + +stop(){ + echo "Stopping bridge.." + cd $WORKDIR + sudo -u "{{ compose_service_user }}" docker stack rm oracle + sleep 2 +} + +status(){ + echo "Bridge status:" + cd $WORKDIR + sudo -u "{{ compose_service_user }}" docker service ls +} + + +case "$1" in + + start) + start + ;; + + stop) + stop + ;; + + status) + status + ;; + + restart) + echo "Restarting bridge.." + stop + start + ;; + + *) + echo $"Usage: $0 {start|stop|restart|status}" + exit 1 + ;; + +esac + +exit 0 diff --git a/deployment/site.yml b/deployment/site.yml index 53a2de0d3..2d53a91f8 100644 --- a/deployment/site.yml +++ b/deployment/site.yml @@ -4,6 +4,11 @@ become: true roles: - { role: oracle } +- name: Install Oracle as a Docker Swarm service + hosts: oracle_swarm + become: true + roles: + - { role: oracle_swarm } - name: Install Monitor hosts: monitor become: true diff --git a/e2e-commons/keystore.json b/e2e-commons/keystore.json new file mode 100644 index 000000000..d8e27456e --- /dev/null +++ b/e2e-commons/keystore.json @@ -0,0 +1 @@ +[{"version":3,"id":"e7e64a1b-5e61-4c17-a473-963d2bbb59e5","address":"d138a69eb2da1c3518e792737c820b23cce62e4b","crypto":{"ciphertext":"f6ddf0b2638fb9fd5777de2aa07937b5ee9bc17acc74c8e6e6580e2dfd0d3de6","cipherparams":{"iv":"bcdbc5af4582887e5cdcf264e8d5b80d"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"f9e621918990e64e278e0fb8cf0343219e1cceaea8547d50fae452ad8f42f231","n":8192,"r":8,"p":1},"mac":"34149cd0b3ddea52588825d403fb75cfb8b864b616d455f75f2de001cc2601ed"}}] diff --git a/oracle/config/base.config.js b/oracle/config/base.config.js index 6dc94902e..4755ebb1e 100644 --- a/oracle/config/base.config.js +++ b/oracle/config/base.config.js @@ -8,13 +8,15 @@ const { FOREIGN_AMB_ABI } = require('../../commons') const { web3Home, web3Foreign } = require('../src/services/web3') -const { add0xPrefix, privateKeyToAddress } = require('../src/utils/utils') +const { add0xPrefix, privateKeyToAddress, loadKeystore } = require('../src/utils/utils') const { EXIT_CODES } = require('../src/utils/constants') const { ORACLE_BRIDGE_MODE, ORACLE_VALIDATOR_ADDRESS, ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, + ORACLE_VALIDATOR_KEYSTORE_PATH, + ORACLE_VALIDATOR_KEYSTORE_PASSWORD, ORACLE_MAX_PROCESSING_TIME, COMMON_HOME_BRIDGE_ADDRESS, COMMON_FOREIGN_BRIDGE_ADDRESS, @@ -81,6 +83,7 @@ const maxProcessingTime = parseInt(ORACLE_MAX_PROCESSING_TIME, 10) || 4 * Math.max(homeConfig.pollingInterval, foreignConfig.pollingInterval) let validatorPrivateKey +let validatorAddress = ORACLE_VALIDATOR_ADDRESS if (ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY) { validatorPrivateKey = add0xPrefix(ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY) const derived = privateKeyToAddress(validatorPrivateKey) @@ -90,12 +93,22 @@ if (ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY) { ) process.exit(EXIT_CODES.INCOMPATIBILITY) } + validatorAddress = derived +} else if (ORACLE_VALIDATOR_KEYSTORE_PATH) { + try { + const keystore = loadKeystore(ORACLE_VALIDATOR_KEYSTORE_PATH, ORACLE_VALIDATOR_KEYSTORE_PASSWORD) + validatorPrivateKey = keystore.privateKey + validatorAddress = keystore.address + } catch (e) { + console.error(`Can't load keystore file: ${e.message}`) + process.exit(EXIT_CODES.INCOMPATIBILITY) + } } module.exports = { eventFilter: {}, validatorPrivateKey, - validatorAddress: ORACLE_VALIDATOR_ADDRESS || privateKeyToAddress(validatorPrivateKey), + validatorAddress, maxProcessingTime, shutdownKey: 'oracle-shutdown', home: homeConfig, diff --git a/oracle/src/utils/utils.js b/oracle/src/utils/utils.js index d4e7a5485..55ba3735a 100644 --- a/oracle/src/utils/utils.js +++ b/oracle/src/utils/utils.js @@ -99,6 +99,11 @@ function privateKeyToAddress(privateKey) { return privateKey ? new Web3().eth.accounts.privateKeyToAccount(add0xPrefix(privateKey)).address : null } +function loadKeystore(keystorePath, password) { + const keystore = JSON.parse(fs.readFileSync(keystorePath).toString()) + return new Web3().eth.accounts.wallet.decrypt(keystore, password)[0] +} + function isGasPriceError(e) { const message = e.message.toLowerCase() return message.includes('replacement transaction underpriced') @@ -195,5 +200,6 @@ module.exports = { getRetrySequence, promiseAny, readAccessListFile, - zipToObject + zipToObject, + loadKeystore }