diff --git a/.circleci/config.yml b/.circleci/config.yml index a0ddf53c5..975db93c2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,7 +11,7 @@ orbs: sudo apt-get clean sudo apt-get update sudo apt-get install dpkg - - run: + - run: name: Install Chrome command: | wget -O chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_77.0.3865.120-1_amd64.deb @@ -89,29 +89,29 @@ jobs: - checkout - run: git submodule update --init - restore_cache: - name: Restore Yarn Package Cache - keys: - - yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }} - - run: git submodule status > submodule.status + name: Restore Yarn Package Cache + keys: + - yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }} + - run: git submodule status > submodule.status - restore_cache: - name: Restore contracts submodule with compiled contracts - keys: - - contracts-{{ checksum "submodule.status" }} + name: Restore contracts submodule with compiled contracts + keys: + - contracts-{{ checksum "submodule.status" }} - run: yarn install --frozen-lockfile - save_cache: - name: Save Yarn Package Cache - key: yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }} - paths: - - ~/.cache/yarn + name: Save Yarn Package Cache + key: yarn-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }} + paths: + - ~/.cache/yarn - run: touch install_deploy.log; test -d contracts/build/contracts || yarn install:deploy &> install_deploy.log - store_artifacts: path: install_deploy.log - run: test -d contracts/build/contracts || yarn compile:contracts - save_cache: - name: Save contracts submodule with compiled contracts - key: contracts-{{ checksum "submodule.status" }} - paths: - - contracts + name: Save contracts submodule with compiled contracts + key: contracts-{{ checksum "submodule.status" }} + paths: + - contracts - save_cache: name: Save initialized project for subsequent jobs key: initialize-{{ .Environment.CIRCLE_SHA1 }} @@ -143,11 +143,11 @@ jobs: oracle-e2e: executor: tokenbridge-orb/docker-node steps: - - checkout - - run: git submodule update --init - - setup_remote_docker: - docker_layer_caching: true - - run: yarn run oracle-e2e + - checkout + - run: git submodule update --init + - setup_remote_docker: + docker_layer_caching: true + - run: yarn run oracle-e2e ui-e2e: executor: tokenbridge-orb/machine-with-docker-caching steps: @@ -161,9 +161,9 @@ jobs: monitor-e2e: executor: tokenbridge-orb/machine-with-docker-caching steps: - - checkout - - run: git submodule update --init - - run: ./monitor-e2e/run-tests.sh + - checkout + - run: git submodule update --init + - run: ./monitor-e2e/run-tests.sh cover: executor: tokenbridge-orb/docker-node steps: @@ -194,7 +194,7 @@ jobs: steps: - checkout - run: git submodule update --init - - run: + - run: name: Run the scenario command: deployment-e2e/molecule.sh monitor no_output_timeout: 40m @@ -210,7 +210,15 @@ jobs: name: Run the scenario command: deployment-e2e/molecule.sh repo no_output_timeout: 40m - + deployment-multiple: + executor: tokenbridge-orb/machine-with-docker-caching + steps: + - checkout + - run: git submodule update --init + - run: + name: Run the scenario + command: deployment-e2e/molecule.sh multiple + no_output_timeout: 40m ultimate: executor: tokenbridge-orb/machine-with-docker-caching parameters: @@ -222,6 +230,11 @@ jobs: type: string ui-e2e-grep: description: "Mocha grep string used to run ui-e2e tests specific to given type of bridge" + default: '' + type: string + oracle-e2e-script: + description: "Yarn script string used to run oracle-e2e tests specific to given type of bridge" + default: '' type: string steps: - checkout @@ -236,12 +249,21 @@ jobs: no_output_timeout: 50m - tokenbridge-orb/wait-for-oracle: redis-key: << parameters.redis-key >> - - run: - name: Run the ui-e2e tests - command: | - nvm use default; - node ./e2e-commons/scripts/blocks.js & - cd ui-e2e; yarn mocha -g "<< parameters.ui-e2e-grep >>" -b ./test.js + - when: + condition: << parameters.ui-e2e-grep >> + steps: + - run: + name: Run the ui-e2e tests + command: | + nvm use default; + node ./e2e-commons/scripts/blocks.js & + cd ui-e2e; yarn mocha -g "<< parameters.ui-e2e-grep >>" -b ./test.js + - when: + condition: << parameters.oracle-e2e-script >> + steps: + - run: + name: Run the oracle-e2e tests + command: cd e2e-commons && docker-compose run e2e yarn workspace oracle-e2e run << parameters.oracle-e2e-script >> workflows: tokenbridge: jobs: @@ -272,18 +294,24 @@ workflows: - deployment-ui - deployment-monitor - deployment-repo + - deployment-multiple - ultimate: - name: "ultimate: native to erc" + name: "ultimate: native to erc" scenario-name: native-to-erc redis-key: native-erc-collected-signatures:lastProcessedBlock ui-e2e-grep: "NATIVE TO ERC" - ultimate: - name: "ultimate: erc to native" + name: "ultimate: erc to native" scenario-name: erc-to-native redis-key: erc-native-collected-signatures:lastProcessedBlock ui-e2e-grep: "ERC TO NATIVE" - ultimate: - name: "ultimate: erc to erc" + name: "ultimate: erc to erc" scenario-name: erc-to-erc redis-key: erc-erc-collected-signatures:lastProcessedBlock ui-e2e-grep: "ERC TO ERC" + - ultimate: + name: "ultimate: amb" + scenario-name: amb + redis-key: amb-collected-signatures:lastProcessedBlock + oracle-e2e-script: "amb" diff --git a/contracts b/contracts index c85aeb737..7e17921ff 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit c85aeb737bfd684b20b99520bd632ba4b8866583 +Subproject commit 7e17921ffc56287678eb54eadd325a7406821ed9 diff --git a/deployment-e2e/molecule/multiple/Dockerfile.j2 b/deployment-e2e/molecule/multiple/Dockerfile.j2 new file mode 100644 index 000000000..e6aa95d30 --- /dev/null +++ b/deployment-e2e/molecule/multiple/Dockerfile.j2 @@ -0,0 +1,14 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi diff --git a/deployment-e2e/molecule/multiple/molecule.yml b/deployment-e2e/molecule/multiple/molecule.yml new file mode 100644 index 000000000..f161410ec --- /dev/null +++ b/deployment-e2e/molecule/multiple/molecule.yml @@ -0,0 +1,59 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: + name: yamllint + enabled: True + options: + config-data: + ignore: ../../hosts.yml +platforms: + - name: multiple-host + groups: + - example + children: + - oracle + - monitor + - ui + image: ubuntu:16.04 + privileged: true + network_mode: host + volumes: + - /var/run/docker.sock:/var/run/docker.sock +provisioner: + name: ansible + lint: + name: ansible-lint + enabled: True + options: + r: ["bug"] + playbooks: + prepare: ../prepare.yml + converge: ../monitor/converge.yml + inventory: + host_vars: + multiple-host: + ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9" + MONITOR_PORT: 3003 + 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 + - syntax + - create + - prepare + - converge + - verify + - destroy diff --git a/deployment-e2e/molecule/multiple/tests/test_multiple.py b/deployment-e2e/molecule/multiple/tests/test_multiple.py new file mode 100644 index 000000000..7feebd25f --- /dev/null +++ b/deployment-e2e/molecule/multiple/tests/test_multiple.py @@ -0,0 +1,32 @@ +import os +import pytest +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +@pytest.mark.parametrize("service", [ + ("poabridge"), + ("tokenbridge-ui"), + ("tokenbridge-monitor") +]) +def test_services(host, service): + assert host.service(service).is_enabled + assert host.service(service).is_running + + +@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"), + ("ui_ui_1"), + ("monitor_monitor_1") +]) +def test_docker_containers(host, name): + container = host.docker(name) + assert container.is_running diff --git a/deployment-e2e/molecule/tests/test_all.py b/deployment-e2e/molecule/tests/test_all.py index 050107caf..55dc8e3bc 100644 --- a/deployment-e2e/molecule/tests/test_all.py +++ b/deployment-e2e/molecule/tests/test_all.py @@ -9,7 +9,6 @@ def test_repo(host): assert host.file('/home/poadocker/bridge').exists assert host.file('/home/poadocker/bridge').is_directory - assert host.file('/home/poadocker/bridge/package.json').exists def test_docker_group(host): diff --git a/deployment-e2e/molecule/ultimate-amb/Dockerfile.j2 b/deployment-e2e/molecule/ultimate-amb/Dockerfile.j2 new file mode 100644 index 000000000..e6aa95d30 --- /dev/null +++ b/deployment-e2e/molecule/ultimate-amb/Dockerfile.j2 @@ -0,0 +1,14 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi diff --git a/deployment-e2e/molecule/ultimate-amb/molecule.yml b/deployment-e2e/molecule/ultimate-amb/molecule.yml new file mode 100644 index 000000000..d03304204 --- /dev/null +++ b/deployment-e2e/molecule/ultimate-amb/molecule.yml @@ -0,0 +1,40 @@ +--- +driver: + name: docker +platforms: + - name: oracle-amb-host + groups: + - ultimate + - amb + children: + - oracle + image: ubuntu:16.04 + privileged: true + network_mode: host + volumes: + - /var/run/docker.sock:/var/run/docker.sock +provisioner: + name: ansible + playbooks: + prepare: ../prepare.yml + converge: ../ultimate-commons/converge.yml + inventory: + host_vars: + oracle-amb-host: + COMMON_HOME_RPC_URL: "http://parity1:8545" + COMMON_FOREIGN_RPC_URL: "http://parity2:8545" + ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b" + ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9" +verifier: + name: testinfra + lint: + name: flake8 +scenario: + name: ultimate-amb + test_sequence: + - cleanup + - destroy + - syntax + - create + - prepare + - converge diff --git a/deployment-e2e/molecule/ultimate-commons/oracle-add-docker-external-network.yml b/deployment-e2e/molecule/ultimate-commons/oracle-add-docker-external-network.yml index 71bd9e077..77cb562fa 100644 --- a/deployment-e2e/molecule/ultimate-commons/oracle-add-docker-external-network.yml +++ b/deployment-e2e/molecule/ultimate-commons/oracle-add-docker-external-network.yml @@ -1,7 +1,7 @@ --- - name: Slurp docker compose file slurp: - src: "/home/poadocker/bridge/oracle/{{ item }}.yml" + src: "/home/poadocker/bridge/oracle/{{ file }}.yml" register: docker_compose_slurp - name: Parse docker compose file set_fact: @@ -23,4 +23,4 @@ - name: Write updated docker file copy: content: "{{ docker_compose_parsed | to_yaml }}" - dest: "/home/poadocker/bridge/oracle/{{ item }}.yml" + dest: "/home/poadocker/bridge/oracle/{{ file }}.yml" diff --git a/deployment-e2e/molecule/ultimate-commons/oracle-docker-compose.yml b/deployment-e2e/molecule/ultimate-commons/oracle-docker-compose.yml index 98661d6a6..23bc83f1d 100644 --- a/deployment-e2e/molecule/ultimate-commons/oracle-docker-compose.yml +++ b/deployment-e2e/molecule/ultimate-commons/oracle-docker-compose.yml @@ -6,11 +6,30 @@ - name: stop the service shell: service poabridge stop + - name: Build current oracle image + shell: docker build -t oracle:ultimate-testing --file oracle/Dockerfile . + delegate_to: 127.0.0.1 + become: false + args: + chdir: "{{ lookup('env', 'PWD') }}/.." + + - name: Replace oracle image + replace: + path: "/home/poadocker/bridge/oracle/{{ item }}.yml" + regexp: 'poanetwork/tokenbridge-oracle:latest' + replace: "oracle:ultimate-testing" + with_items: + - docker-compose + - docker-compose-transfer + - docker-compose-erc-native + - include_tasks: oracle-add-docker-external-network.yml with_items: - docker-compose - docker-compose-transfer - docker-compose-erc-native + loop_control: + loop_var: file - name: start the service shell: service poabridge start diff --git a/deployment/group_vars/amb.yml b/deployment/group_vars/amb.yml new file mode 100644 index 000000000..b2329e721 --- /dev/null +++ b/deployment/group_vars/amb.yml @@ -0,0 +1,5 @@ +--- +ORACLE_BRIDGE_MODE: "ARBITRARY_MESSAGE" +COMMON_HOME_BRIDGE_ADDRESS: "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0" +COMMON_FOREIGN_BRIDGE_ADDRESS: "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0" +MONITOR_PORT: 3013 diff --git a/deployment/roles/common/tasks/main.yml b/deployment/roles/common/tasks/main.yml index d78b1509c..763e2c181 100644 --- a/deployment/roles/common/tasks/main.yml +++ b/deployment/roles/common/tasks/main.yml @@ -1,6 +1,6 @@ --- - name: Check if component is already deployed - shell: "test -f {{ bridge_path }}/{{ component }}/docker-compose.yml && echo 'true'" + shell: "test -f {{ bridge_path }}/{{ component }}/.env && echo 'true'" ignore_errors: True register: already_deployed when: check_deployed is defined @@ -14,7 +14,7 @@ - name: Include repo tasks include_tasks: repo.yml - when: skip_task != true + when: skip_task != true and skip_repo is undefined - name: Include logging tasks include_tasks: logging.yml diff --git a/deployment/roles/monitor/meta/main.yml b/deployment/roles/monitor/meta/main.yml index c981746d7..a3c7f2db8 100644 --- a/deployment/roles/monitor/meta/main.yml +++ b/deployment/roles/monitor/meta/main.yml @@ -1,3 +1,3 @@ --- dependencies: - - { role: common, check_deployed: true, component: 'monitor' } + - { role: common, skip_repo: true, check_deployed: true, component: 'monitor' } diff --git a/deployment/roles/monitor/tasks/jumpbox.yml b/deployment/roles/monitor/tasks/jumpbox.yml index 9374257a6..5e230b79f 100644 --- a/deployment/roles/monitor/tasks/jumpbox.yml +++ b/deployment/roles/monitor/tasks/jumpbox.yml @@ -1,5 +1,5 @@ --- -- name: Build the containers - shell: docker-compose build +- name: Pull the containers images + shell: docker-compose pull args: chdir: "{{ bridge_path }}/monitor" diff --git a/deployment/roles/monitor/tasks/pre_config.yml b/deployment/roles/monitor/tasks/pre_config.yml index cc76e62bd..4ef7c1557 100644 --- a/deployment/roles/monitor/tasks/pre_config.yml +++ b/deployment/roles/monitor/tasks/pre_config.yml @@ -1,10 +1,46 @@ --- +- name: Create configs directory + file: + path: "{{ bridge_path }}/monitor/configs" + state: directory + mode: '0755' + when: skip_task != true + +- name: Create responses directory + file: + path: "{{ bridge_path }}/monitor/responses" + state: directory + mode: '0755' + when: skip_task != true + +- name: Create scripts directory + file: + path: "{{ bridge_path }}/monitor/scripts" + state: directory + mode: '0755' + when: skip_task != true + - name: Install .env config template: src: .env.j2 dest: "{{ bridge_path }}/monitor/.env" when: skip_task != true +- name: Copy docker-compose file + copy: + src: ../../../../monitor/docker-compose.yml + dest: "{{ bridge_path }}/monitor/docker-compose.yml" + mode: '0755' + when: skip_task != true + +- name: Copy script file + copy: + src: ../../../../monitor/scripts/getBridgeStats.sh + dest: "{{ bridge_path }}/monitor/scripts/getBridgeStats.sh" + owner: "{{ compose_service_user }}" + mode: '0755' + when: skip_task != true + - name: Install bridge config env template: src: config.env.j2 diff --git a/deployment/roles/monitor/tasks/servinstall.yml b/deployment/roles/monitor/tasks/servinstall.yml index 888d571e7..3cafae4b9 100644 --- a/deployment/roles/monitor/tasks/servinstall.yml +++ b/deployment/roles/monitor/tasks/servinstall.yml @@ -1,6 +1,5 @@ # This role creates a tokenbridge-monitor service which is designed to manage docker-compose monitor deployment. # /etc/init.d/tokenbridge-monitor start, status, stop, restart - does what the services usually do in such cases. -# /etc/init.d/tokenbridge-monitor rebuild - builds a new monitor deployment from scratch. --- - name: "Set the service" template: diff --git a/deployment/roles/monitor/templates/tokenbridge-monitor.j2 b/deployment/roles/monitor/templates/tokenbridge-monitor.j2 index 7ff4b6889..0198acdac 100644 --- a/deployment/roles/monitor/templates/tokenbridge-monitor.j2 +++ b/deployment/roles/monitor/templates/tokenbridge-monitor.j2 @@ -34,14 +34,6 @@ status(){ sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose ps } -rebuild(){ - echo "Rebuild TokenBridge Monitor.." - cd $WORKDIR - sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose down -v - sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose rm -fv - sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose up --detach --force-recreate --no-deps --build -} - case "$1" in @@ -63,12 +55,8 @@ case "$1" in start ;; - rebuild) - rebuild - ;; - *) - echo $"Usage: $0 {start|stop|restart|rebuild|status}" + echo $"Usage: $0 {start|stop|restart|status}" exit 1 ;; diff --git a/deployment/roles/oracle/meta/main.yml b/deployment/roles/oracle/meta/main.yml index fdda41bb3..566d62a0a 100644 --- a/deployment/roles/oracle/meta/main.yml +++ b/deployment/roles/oracle/meta/main.yml @@ -1,3 +1,3 @@ --- dependencies: - - role: common + - { role: common, skip_repo: true } diff --git a/deployment/roles/oracle/tasks/jumpbox.yml b/deployment/roles/oracle/tasks/jumpbox.yml index 9bfde795a..3d1dcf1cf 100644 --- a/deployment/roles/oracle/tasks/jumpbox.yml +++ b/deployment/roles/oracle/tasks/jumpbox.yml @@ -1,5 +1,5 @@ --- -- name: Build the containers - shell: docker-compose build +- name: Pull the containers images + shell: docker-compose pull args: chdir: "{{ bridge_path }}/oracle" diff --git a/deployment/roles/oracle/tasks/logging.yml b/deployment/roles/oracle/tasks/logging.yml index 60011f37b..46bf3afcd 100644 --- a/deployment/roles/oracle/tasks/logging.yml +++ b/deployment/roles/oracle/tasks/logging.yml @@ -4,6 +4,8 @@ - docker-compose - docker-compose-transfer - docker-compose-erc-native + loop_control: + loop_var: file - name: Set the local container logs configuration file template: diff --git a/deployment/roles/oracle/tasks/logging_by_syslog.yml b/deployment/roles/oracle/tasks/logging_by_syslog.yml index 4ac50828b..0cfce76e1 100644 --- a/deployment/roles/oracle/tasks/logging_by_syslog.yml +++ b/deployment/roles/oracle/tasks/logging_by_syslog.yml @@ -1,7 +1,7 @@ --- - name: Slurp docker compose file slurp: - src: "{{ bridge_path }}/oracle/{{ item }}.yml" + src: "{{ bridge_path }}/oracle/{{ file }}.yml" register: docker_compose_slurp - name: Parse docker compose file @@ -16,4 +16,4 @@ - name: Write updated docker file copy: content: "{{ docker_compose_parsed | to_yaml }}" - dest: "{{ bridge_path }}/oracle/{{ item }}.yml" + dest: "{{ bridge_path }}/oracle/{{ file }}.yml" diff --git a/deployment/roles/oracle/tasks/post_config.yml b/deployment/roles/oracle/tasks/post_config.yml index 4eab39d81..fc98cb603 100644 --- a/deployment/roles/oracle/tasks/post_config.yml +++ b/deployment/roles/oracle/tasks/post_config.yml @@ -1,7 +1,7 @@ --- - name: Get blocks become_user: "{{ compose_service_user }}" - shell: docker-compose run --entrypoint "node scripts/getValidatorStartBlocks.js" bridge_affirmation + shell: docker-compose run --rm --entrypoint "node scripts/getValidatorStartBlocks.js" bridge_affirmation args: chdir: "{{ bridge_path }}/oracle" register: BLOCKS @@ -18,7 +18,7 @@ - name: Get validator address become_user: "{{ compose_service_user }}" - shell: docker-compose run -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY="{{ ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY }}" --entrypoint "node scripts/privateKeyToAddress.js" bridge_affirmation + shell: docker-compose run --rm -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY="{{ ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY }}" --entrypoint "node scripts/privateKeyToAddress.js" bridge_affirmation args: chdir: "{{ bridge_path }}/oracle" register: VADDRESS @@ -29,7 +29,7 @@ - name: Get foreign erc type become_user: "{{ compose_service_user }}" - shell: docker-compose run --entrypoint "node scripts/initialChecks.js" bridge_affirmation + shell: docker-compose run --rm --entrypoint "node scripts/initialChecks.js" bridge_affirmation args: chdir: "{{ bridge_path }}/oracle" register: ERCTYPE diff --git a/deployment/roles/oracle/tasks/pre_config.yml b/deployment/roles/oracle/tasks/pre_config.yml index e398c93d5..72779cb9c 100644 --- a/deployment/roles/oracle/tasks/pre_config.yml +++ b/deployment/roles/oracle/tasks/pre_config.yml @@ -1,5 +1,21 @@ --- +- name: Create oracle directory + file: + path: "{{ bridge_path }}/oracle" + state: directory + mode: '0755' + - name: Install .env config template: src: .env.j2 dest: "{{ bridge_path }}/oracle/.env" + +- name: Copy docker-compose files + copy: + src: ../../../../oracle/{{ item }} + dest: "{{ bridge_path }}/oracle/" + mode: '0755' + with_items: + - docker-compose.yml + - docker-compose-transfer.yml + - docker-compose-erc-native.yml diff --git a/deployment/roles/oracle/tasks/servinstall.yml b/deployment/roles/oracle/tasks/servinstall.yml index 24103ed00..74ff01bf4 100644 --- a/deployment/roles/oracle/tasks/servinstall.yml +++ b/deployment/roles/oracle/tasks/servinstall.yml @@ -1,6 +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. --- - name: "Set poabridge service" template: diff --git a/deployment/roles/oracle/templates/poabridge.j2 b/deployment/roles/oracle/templates/poabridge.j2 index 370c9cdf3..31f7b1a5a 100644 --- a/deployment/roles/oracle/templates/poabridge.j2 +++ b/deployment/roles/oracle/templates/poabridge.j2 @@ -52,14 +52,6 @@ status(){ sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose $composefileoverride ps } -rebuild(){ - echo "Rebuild bridge.." - cd $WORKDIR - sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose $composefileoverride down -v - sudo -u "{{ compose_service_user }}" /usr/local/bin/docker-compose $composefileoverride rm -fv - sudo -u "{{ compose_service_user }}" ORACLE_VALIDATOR_ADDRESS=$vaddr ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=$vkey /usr/local/bin/docker-compose $composefileoverride up --detach --force-recreate --no-deps --build -} - case "$1" in @@ -81,12 +73,8 @@ case "$1" in start ;; - rebuild) - rebuild - ;; - *) - echo $"Usage: $0 {start|stop|restart|rebuild|status}" + echo $"Usage: $0 {start|stop|restart|status}" exit 1 ;; diff --git a/e2e-commons/constants.json b/e2e-commons/constants.json index ae28c3397..9f5c8334f 100644 --- a/e2e-commons/constants.json +++ b/e2e-commons/constants.json @@ -7,10 +7,26 @@ "address": "0xcca2fb44C8C36E51f743269d6F484Fd027B9F9Aa", "privateKey": "0xcf954e07e6a439faf392eb474e95ddb444c2ca444847f2ad6ecc79e1a585e2b8" }, + "thirdUser": { + "address": "0x441cc8537aB6cE63d060b63F3A44eE021d62e6cF", + "privateKey": "0xd3915199f27691d7784cb01ab0c7220308053b229f95d592e97493326314a8d0" + }, + "fourthUser": { + "address": "0x3CC5baAB679eC0732C175760079Bf48F564ad26B", + "privateKey": "0xedb53ee050631b7914d5f1a66c2f0d2df3ec85a9ed2a9616b16a7b1b7a10b8d1" + }, "validator": { "address": "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b", "privateKey": "0x8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9" }, + "secondValidator": { + "address": "0xdCC784657C78054aa61FbcFFd2605F32374816A4", + "privateKey": "0x5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513" + }, + "thirdValidator": { + "address": "0xDcef88209a20D52165230104B245803C3269454d", + "privateKey": "0xf877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1" + }, "blockGenerator": { "address": "0xB4579fd5AfEaB60B03Db3F408AAdD315035943f7", "privateKey": "0xd6143d390d8b28c33601bb0fe29392fb1c35c24ccfe8722c09c2bdd6ada2699f" diff --git a/e2e-commons/contracts-envs/amb.env b/e2e-commons/contracts-envs/amb.env index 9335c5044..e575f0b53 100644 --- a/e2e-commons/contracts-envs/amb.env +++ b/e2e-commons/contracts-envs/amb.env @@ -22,4 +22,4 @@ FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=1 FOREIGN_GAS_PRICE=10000000000 REQUIRED_NUMBER_OF_VALIDATORS=1 -VALIDATORS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b +VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d" diff --git a/e2e-commons/contracts-envs/erc-to-erc.env b/e2e-commons/contracts-envs/erc-to-erc.env index f1f4daa8a..1c9a2004a 100644 --- a/e2e-commons/contracts-envs/erc-to-erc.env +++ b/e2e-commons/contracts-envs/erc-to-erc.env @@ -34,8 +34,7 @@ FOREIGN_REWARDABLE=false ERC20_TOKEN_ADDRESS=0x3C665A31199694Bf723fD08844AD290207B5797f REQUIRED_NUMBER_OF_VALIDATORS=1 -VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b" -VALIDATORS_REWARD_ACCOUNTS=0x0000000000000000000000000000000000000000 +VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d" BLOCK_REWARD_ADDRESS=0x0000000000000000000000000000000000000000 DPOS_STAKING_ADDRESS=0x0000000000000000000000000000000000000000 ERC20_EXTENDED_BY_ERC677=false diff --git a/e2e-commons/contracts-envs/erc-to-native.env b/e2e-commons/contracts-envs/erc-to-native.env index f79916737..8a7ccac7b 100644 --- a/e2e-commons/contracts-envs/erc-to-native.env +++ b/e2e-commons/contracts-envs/erc-to-native.env @@ -35,5 +35,4 @@ BLOCK_REWARD_ADDRESS=0xF9698Eb93702dfdd0e2d802088d4c21822a8A977 ERC20_TOKEN_ADDRESS=0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359 REQUIRED_NUMBER_OF_VALIDATORS=1 -VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b" -VALIDATORS_REWARD_ACCOUNTS=0x0000000000000000000000000000000000000000 +VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d" diff --git a/e2e-commons/contracts-envs/native-to-erc.env b/e2e-commons/contracts-envs/native-to-erc.env index 7e16f2c76..6620aa46e 100644 --- a/e2e-commons/contracts-envs/native-to-erc.env +++ b/e2e-commons/contracts-envs/native-to-erc.env @@ -34,6 +34,5 @@ FOREIGN_GAS_PRICE=10000000000 FOREIGN_REWARDABLE=false REQUIRED_NUMBER_OF_VALIDATORS=1 -VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b" -VALIDATORS_REWARD_ACCOUNTS=0x0000000000000000000000000000000000000000 +VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d" BLOCK_REWARD_ADDRESS=0x0000000000000000000000000000000000000000 diff --git a/e2e-commons/docker-compose.yml b/e2e-commons/docker-compose.yml index 722af57c0..a399ed265 100644 --- a/e2e-commons/docker-compose.yml +++ b/e2e-commons/docker-compose.yml @@ -24,16 +24,13 @@ services: - ultimate rabbit: image: "rabbitmq:3-management" - ports: - - "15672:15672" networks: - ultimate oracle: build: context: .. dockerfile: oracle/Dockerfile - args: - DOT_ENV_PATH: e2e-commons/components-envs/oracle.env + env_file: ../e2e-commons/components-envs/oracle.env environment: - NODE_ENV=production command: "true" @@ -43,8 +40,7 @@ services: build: context: .. dockerfile: oracle/Dockerfile - args: - DOT_ENV_PATH: e2e-commons/components-envs/oracle-erc20.env + env_file: ../e2e-commons/components-envs/oracle-erc20.env environment: - NODE_ENV=production command: "true" @@ -54,8 +50,7 @@ services: build: context: .. dockerfile: oracle/Dockerfile - args: - DOT_ENV_PATH: e2e-commons/components-envs/oracle-erc20-native.env + env_file: ../e2e-commons/components-envs/oracle-erc20-native.env environment: - NODE_ENV=production command: "true" @@ -65,8 +60,7 @@ services: build: context: .. dockerfile: oracle/Dockerfile - args: - DOT_ENV_PATH: e2e-commons/components-envs/oracle-amb.env + env_file: ../e2e-commons/components-envs/oracle-amb.env environment: - NODE_ENV=production command: "true" diff --git a/e2e-commons/down.sh b/e2e-commons/down.sh index 06e846fea..8eef31552 100755 --- a/e2e-commons/down.sh +++ b/e2e-commons/down.sh @@ -5,4 +5,6 @@ if [ $CI ]; then exit $rc; fi ps | grep node | grep -v grep | awk '{print "kill " $1}' | /bin/bash docker-compose down +docker-compose -p validator2 down +docker-compose -p validator3 down docker network rm ultimate || true diff --git a/e2e-commons/up.sh b/e2e-commons/up.sh index 5a8053b38..d30d0656f 100755 --- a/e2e-commons/up.sh +++ b/e2e-commons/up.sh @@ -7,6 +7,29 @@ docker-compose build docker network create --driver bridge ultimate || true docker-compose up -d parity1 parity2 e2e +startValidator () { + docker-compose $1 run -d --name $4 redis + docker-compose $1 run -d --name $5 rabbit + docker-compose $1 run $2 $3 -d oracle yarn watcher:signature-request + docker-compose $1 run $2 $3 -d oracle yarn watcher:collected-signatures + docker-compose $1 run $2 $3 -d oracle yarn watcher:affirmation-request + docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:signature-request + docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:collected-signatures + docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:affirmation-request + docker-compose $1 run $2 $3 -d oracle-erc20 yarn watcher:transfer + docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:signature-request + docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:collected-signatures + docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:affirmation-request + docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:transfer + docker-compose $1 run $2 $3 -d oracle-erc20-native yarn watcher:half-duplex-transfer + docker-compose $1 run $2 $3 -d oracle-erc20-native yarn worker:swap-tokens + docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:signature-request + docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:collected-signatures + docker-compose $1 run $2 $3 -d oracle-amb yarn watcher:affirmation-request + docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:home + docker-compose $1 run $2 $3 -d oracle-erc20-native yarn sender:foreign +} + while [ "$1" != "" ]; do if [ "$1" == "oracle" ]; then docker-compose up -d redis rabbit oracle oracle-erc20 oracle-erc20-native oracle-amb @@ -31,6 +54,20 @@ while [ "$1" != "" ]; do docker-compose run -d oracle yarn sender:foreign fi + if [ "$1" == "oracle-validator-2" ]; then + oracle2name="-p validator2" + oracle2Values="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4 -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513" + oracle2comp="-e ORACLE_QUEUE_URL=amqp://rabbit2 -e ORACLE_REDIS_URL=redis://redis2" + startValidator "$oracle2name" "$oracle2Values" "$oracle2comp" "redis2" "rabbit2" + fi + + if [ "$1" == "oracle-validator-3" ]; then + oracle3name="-p validator3" + oracle3Values="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1" + oracle3comp="-e ORACLE_QUEUE_URL=amqp://rabbit3 -e ORACLE_REDIS_URL=redis://redis3" + startValidator "$oracle3name" "$oracle3Values" "$oracle3comp" "redis3" "rabbit3" + fi + if [ "$1" == "ui" ]; then docker-compose up -d ui ui-erc20 ui-erc20-native @@ -63,5 +100,9 @@ while [ "$1" != "" ]; do ../deployment-e2e/molecule.sh ultimate-erc-to-erc fi + if [ "$1" == "amb" ]; then + ../deployment-e2e/molecule.sh ultimate-amb + fi + shift # Shift all the parameters down by one done diff --git a/monitor/checkWorker3.js b/monitor/checkWorker3.js index c86d96117..a4fd2416b 100644 --- a/monitor/checkWorker3.js +++ b/monitor/checkWorker3.js @@ -1,19 +1,27 @@ +const Web3 = require('web3') const logger = require('./logger')('checkWorker3') const stuckTransfers = require('./stuckTransfers') const { writeFile, createDir } = require('./utils/file') -const { MONITOR_BRIDGE_NAME } = process.env +const { MONITOR_BRIDGE_NAME, COMMON_HOME_BRIDGE_ADDRESS, COMMON_HOME_RPC_URL } = process.env +const { getBridgeMode, HOME_NATIVE_TO_ERC_ABI, BRIDGE_MODES } = require('../commons') + +const homeProvider = new Web3.providers.HttpProvider(COMMON_HOME_RPC_URL) +const web3Home = new Web3(homeProvider) 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)) - transfers.ok = transfers.total.length === 0 - writeFile(`/responses/${MONITOR_BRIDGE_NAME}/stuckTransfers.json`, transfers) - logger.debug('Done') + const homeBridge = new web3Home.eth.Contract(HOME_NATIVE_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS) + const bridgeMode = await getBridgeMode(homeBridge) + if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC_V1) { + createDir(`/responses/${MONITOR_BRIDGE_NAME}`) + logger.debug('calling stuckTransfers()') + const transfers = await stuckTransfers() + if (!transfers) throw new Error('transfers is empty: ' + JSON.stringify(transfers)) + transfers.ok = transfers.total.length === 0 + writeFile(`/responses/${MONITOR_BRIDGE_NAME}/stuckTransfers.json`, transfers) + logger.debug('Done') + } } catch (e) { logger.error('checkWorker3.js', e) } diff --git a/monitor/docker-compose.yml b/monitor/docker-compose.yml index 993c0903e..8d0661e99 100644 --- a/monitor/docker-compose.yml +++ b/monitor/docker-compose.yml @@ -2,9 +2,7 @@ version: '2.4' services: monitor: - build: - context: .. - dockerfile: monitor/Dockerfile + image: poanetwork/tokenbridge-monitor:latest ports: - "${MONITOR_PORT}:${MONITOR_PORT}" env_file: ./.env diff --git a/monitor/index.js b/monitor/index.js index 076af6db6..a235d2cd3 100644 --- a/monitor/index.js +++ b/monitor/index.js @@ -5,6 +5,7 @@ const { readFile } = require('./utils/file') const app = express() const bridgeRouter = express.Router({ mergeParams: true }) +app.get('/favicon.ico', (req, res) => res.sendStatus(204)) app.use('/:bridgeName', bridgeRouter) bridgeRouter.get('/', async (req, res, next) => { diff --git a/monitor/package.json b/monitor/package.json index d314fa984..978df3f17 100644 --- a/monitor/package.json +++ b/monitor/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "check-all": "timeout -s 9 5m node checkWorker.js && timeout -s 9 5m node checkWorker2.js", + "check-all": "timeout -s 9 5m node checkWorker.js && timeout -s 9 5m node checkWorker2.js && timeout -s 9 5m node checkWorker3.js", "start": "node index.js", "check-and-start": "yarn check-all && yarn start", "lint": "eslint . --ignore-path ../.eslintignore", diff --git a/monitor/scripts/getBridgeStats.sh b/monitor/scripts/getBridgeStats.sh index 556c3b631..5a90b882a 100755 --- a/monitor/scripts/getBridgeStats.sh +++ b/monitor/scripts/getBridgeStats.sh @@ -4,7 +4,7 @@ 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' + docker run --rm --env-file $file -v $(pwd)/responses:/mono/monitor/responses poanetwork/tokenbridge-monitor:latest /bin/bash -c 'yarn check-all' done else echo "Monitor is not running, skipping checks." diff --git a/oracle-e2e/package.json b/oracle-e2e/package.json index 3deef31dc..53bd2ed00 100644 --- a/oracle-e2e/package.json +++ b/oracle-e2e/package.json @@ -6,7 +6,7 @@ "scripts": { "start": "mocha", "lint": "eslint . --ignore-path ../.eslintignore", - "native-to-erc": "mocha test/nativeToErc.js" + "amb": "ULTIMATE=true mocha test/amb.js" }, "author": "", "license": "ISC", diff --git a/oracle-e2e/run-tests.sh b/oracle-e2e/run-tests.sh index 74599c370..a2aba6c69 100755 --- a/oracle-e2e/run-tests.sh +++ b/oracle-e2e/run-tests.sh @@ -1,6 +1,6 @@ cd $(dirname $0) -../e2e-commons/up.sh deploy oracle +../e2e-commons/up.sh deploy oracle oracle-validator-2 oracle-validator-3 docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run start rc=$? diff --git a/oracle-e2e/test/amb.js b/oracle-e2e/test/amb.js index 351c4b96b..f1b24ea40 100644 --- a/oracle-e2e/test/amb.js +++ b/oracle-e2e/test/amb.js @@ -1,22 +1,56 @@ const Web3 = require('web3') const assert = require('assert') const promiseRetry = require('promise-retry') -const { user, homeRPC, foreignRPC, amb } = require('../../e2e-commons/constants.json') +const { user, homeRPC, foreignRPC, amb, validator } = require('../../e2e-commons/constants.json') const { generateNewBlock } = require('../../e2e-commons/utils') -const { BOX_ABI } = require('../../commons') +const { BOX_ABI, HOME_AMB_ABI, FOREIGN_AMB_ABI } = require('../../commons') +const { setRequiredSignatures } = require('./utils') const { toBN } = Web3.utils const homeWeb3 = new Web3(new Web3.providers.HttpProvider(homeRPC.URL)) const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(foreignRPC.URL)) +const COMMON_HOME_BRIDGE_ADDRESS = amb.home +const COMMON_FOREIGN_BRIDGE_ADDRESS = amb.foreign + homeWeb3.eth.accounts.wallet.add(user.privateKey) +homeWeb3.eth.accounts.wallet.add(validator.privateKey) foreignWeb3.eth.accounts.wallet.add(user.privateKey) +foreignWeb3.eth.accounts.wallet.add(validator.privateKey) const homeBox = new homeWeb3.eth.Contract(BOX_ABI, amb.homeBox) const foreignBox = new foreignWeb3.eth.Contract(BOX_ABI, amb.foreignBox) +const homeBridge = new homeWeb3.eth.Contract(HOME_AMB_ABI, COMMON_HOME_BRIDGE_ADDRESS) +const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS) describe('arbitrary message bridging', () => { + before(async () => { + // Only 1 validator is used in ultimate tests + if (process.env.ULTIMATE !== 'true') { + // Set 2 required signatures for home bridge + await setRequiredSignatures({ + bridgeContract: homeBridge, + web3: homeWeb3, + requiredSignatures: 2, + options: { + from: validator.address, + gas: '4000000' + } + }) + + // Set 2 required signatures for foreign bridge + await setRequiredSignatures({ + bridgeContract: foreignBridge, + web3: foreignWeb3, + requiredSignatures: 2, + options: { + from: validator.address, + gas: '4000000' + } + }) + } + }) describe('Home to Foreign', () => { describe('Subsidized Mode', () => { it('should bridge message', async () => { @@ -59,6 +93,7 @@ describe('arbitrary message bridging', () => { // check that value changed and balance decreased await promiseRetry(async retry => { + await generateNewBlock(homeWeb3, user.address) const value = await foreignBox.methods.value().call() if (!toBN(value).eq(toBN(newValue))) { retry() diff --git a/oracle-e2e/test/ercToErc.js b/oracle-e2e/test/ercToErc.js index ef155bf80..2fa012730 100644 --- a/oracle-e2e/test/ercToErc.js +++ b/oracle-e2e/test/ercToErc.js @@ -1,9 +1,10 @@ const Web3 = require('web3') const assert = require('assert') const promiseRetry = require('promise-retry') -const { user, secondUser, ercToErcBridge, homeRPC, foreignRPC } = require('../../e2e-commons/constants.json') -const { ERC677_BRIDGE_TOKEN_ABI, FOREIGN_ERC_TO_NATIVE_ABI } = require('../../commons') +const { user, secondUser, ercToErcBridge, homeRPC, foreignRPC, validator } = require('../../e2e-commons/constants.json') +const { ERC677_BRIDGE_TOKEN_ABI, FOREIGN_ERC_TO_NATIVE_ABI, HOME_ERC_TO_ERC_ABI } = require('../../commons') const { generateNewBlock } = require('../../e2e-commons/utils') +const { setRequiredSignatures } = require('./utils') const homeWeb3 = new Web3(new Web3.providers.HttpProvider(homeRPC.URL)) const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(foreignRPC.URL)) @@ -14,13 +15,39 @@ const COMMON_FOREIGN_BRIDGE_ADDRESS = ercToErcBridge.foreign const { toBN } = foreignWeb3.utils homeWeb3.eth.accounts.wallet.add(user.privateKey) +homeWeb3.eth.accounts.wallet.add(validator.privateKey) foreignWeb3.eth.accounts.wallet.add(user.privateKey) +foreignWeb3.eth.accounts.wallet.add(validator.privateKey) const erc20Token = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, ercToErcBridge.foreignToken) const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS) const erc677Token = new homeWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, ercToErcBridge.homeToken) +const homeBridge = new homeWeb3.eth.Contract(HOME_ERC_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS) describe('erc to erc', () => { + before(async () => { + // Set 2 required signatures for home bridge + await setRequiredSignatures({ + bridgeContract: homeBridge, + web3: homeWeb3, + requiredSignatures: 2, + options: { + from: validator.address, + gas: '4000000' + } + }) + + // Set 2 required signatures for foreign bridge + await setRequiredSignatures({ + bridgeContract: foreignBridge, + web3: foreignWeb3, + requiredSignatures: 2, + options: { + from: validator.address, + gas: '4000000' + } + }) + }) it('should convert tokens in foreign to tokens in home', async () => { const balance = await erc20Token.methods.balanceOf(user.address).call() assert(!toBN(balance).isZero(), 'Account should have tokens') @@ -132,6 +159,7 @@ describe('erc to erc', () => { // check that balance increases await promiseRetry(async retry => { + await generateNewBlock(homeWeb3, user.address) const balance = await erc20Token.methods.balanceOf(user.address).call() if (toBN(balance).lte(toBN(originalBalance))) { retry() diff --git a/oracle-e2e/test/ercToNative.js b/oracle-e2e/test/ercToNative.js index ba4746933..b1c925e44 100644 --- a/oracle-e2e/test/ercToNative.js +++ b/oracle-e2e/test/ercToNative.js @@ -9,8 +9,9 @@ const { homeRPC, foreignRPC } = require('../../e2e-commons/constants.json') -const { ERC677_BRIDGE_TOKEN_ABI, FOREIGN_ERC_TO_NATIVE_ABI, SAI_TOP } = require('../../commons') +const { ERC677_BRIDGE_TOKEN_ABI, FOREIGN_ERC_TO_NATIVE_ABI, SAI_TOP, HOME_ERC_TO_NATIVE_ABI } = require('../../commons') const { generateNewBlock } = require('../../e2e-commons/utils') +const { setRequiredSignatures } = require('./utils') const homeWeb3 = new Web3(new Web3.providers.HttpProvider(homeRPC.URL)) const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(foreignRPC.URL)) @@ -21,11 +22,13 @@ const COMMON_FOREIGN_BRIDGE_ADDRESS = ercToNativeBridge.foreign const { toBN } = foreignWeb3.utils homeWeb3.eth.accounts.wallet.add(user.privateKey) +homeWeb3.eth.accounts.wallet.add(validator.privateKey) foreignWeb3.eth.accounts.wallet.add(user.privateKey) foreignWeb3.eth.accounts.wallet.add(validator.privateKey) const erc20Token = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, ercToNativeBridge.foreignToken) const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS) +const homeBridge = new homeWeb3.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS) describe('erc to native', () => { let halfDuplexTokenAddress @@ -33,6 +36,28 @@ describe('erc to native', () => { before(async () => { halfDuplexTokenAddress = await foreignBridge.methods.halfDuplexErc20token().call() halfDuplexToken = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, halfDuplexTokenAddress) + + // Set 2 required signatures for home bridge + await setRequiredSignatures({ + bridgeContract: homeBridge, + web3: homeWeb3, + requiredSignatures: 2, + options: { + from: validator.address, + gas: '4000000' + } + }) + + // Set 2 required signatures for foreign bridge + await setRequiredSignatures({ + bridgeContract: foreignBridge, + web3: foreignWeb3, + requiredSignatures: 2, + options: { + from: validator.address, + gas: '4000000' + } + }) }) it('should continue working after migration', async () => { const originalBalanceOnHome = await homeWeb3.eth.getBalance(user.address) @@ -81,7 +106,7 @@ describe('erc to native', () => { }) // update min threshold for swap - await foreignBridge.methods.setMinHDTokenBalance(foreignWeb3.utils.toWei('1', 'ether')).send({ + await foreignBridge.methods.setMinHDTokenBalance(foreignWeb3.utils.toWei('2', 'ether')).send({ from: validator.address, gas: '1000000' }) @@ -494,6 +519,7 @@ describe('erc to native', () => { // check that balance increases await promiseRetry(async retry => { + await generateNewBlock(homeWeb3, user.address) const balance = await erc20Token.methods.balanceOf(user.address).call() if (toBN(balance).lte(toBN(originalBalance))) { retry() diff --git a/oracle-e2e/test/mocha.opts b/oracle-e2e/test/mocha.opts index 9be9f5643..4effd0565 100644 --- a/oracle-e2e/test/mocha.opts +++ b/oracle-e2e/test/mocha.opts @@ -1 +1 @@ ---timeout 30000 +--timeout 120000 diff --git a/oracle-e2e/test/nativeToErc.js b/oracle-e2e/test/nativeToErc.js index ab1d9e3cf..bc07fa312 100644 --- a/oracle-e2e/test/nativeToErc.js +++ b/oracle-e2e/test/nativeToErc.js @@ -4,13 +4,18 @@ const promiseRetry = require('promise-retry') const { user, validator, + secondValidator, + thirdValidator, nativeToErcBridge, secondUser, + thirdUser, + fourthUser, homeRPC, foreignRPC } = require('../../e2e-commons/constants.json') -const { ERC677_BRIDGE_TOKEN_ABI } = require('../../commons') +const { ERC677_BRIDGE_TOKEN_ABI, HOME_NATIVE_TO_ERC_ABI, FOREIGN_NATIVE_TO_ERC_ABI } = require('../../commons') const { generateNewBlock } = require('../../e2e-commons/utils') +const { setRequiredSignatures } = require('./utils') const homeWeb3 = new Web3(new Web3.providers.HttpProvider(homeRPC.URL)) const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(foreignRPC.URL)) @@ -22,15 +27,48 @@ const COMMON_FOREIGN_BRIDGE_ADDRESS = nativeToErcBridge.foreign homeWeb3.eth.accounts.wallet.add(user.privateKey) homeWeb3.eth.accounts.wallet.add(validator.privateKey) homeWeb3.eth.accounts.wallet.add(secondUser.privateKey) +homeWeb3.eth.accounts.wallet.add(secondValidator.privateKey) +homeWeb3.eth.accounts.wallet.add(thirdValidator.privateKey) +homeWeb3.eth.accounts.wallet.add(thirdUser.privateKey) +homeWeb3.eth.accounts.wallet.add(fourthUser.privateKey) foreignWeb3.eth.accounts.wallet.add(user.privateKey) foreignWeb3.eth.accounts.wallet.add(validator.privateKey) foreignWeb3.eth.accounts.wallet.add(secondUser.privateKey) +foreignWeb3.eth.accounts.wallet.add(secondValidator.privateKey) +foreignWeb3.eth.accounts.wallet.add(thirdValidator.privateKey) +foreignWeb3.eth.accounts.wallet.add(thirdUser.privateKey) +foreignWeb3.eth.accounts.wallet.add(fourthUser.privateKey) const token = new foreignWeb3.eth.Contract(ERC677_BRIDGE_TOKEN_ABI, nativeToErcBridge.foreignToken) +const homeBridge = new homeWeb3.eth.Contract(HOME_NATIVE_TO_ERC_ABI, COMMON_HOME_BRIDGE_ADDRESS) +const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_NATIVE_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS) const sleep = timeout => new Promise(res => setTimeout(res, timeout)) describe('native to erc', () => { + before(async () => { + // Set 2 required signatures for home bridge + await setRequiredSignatures({ + bridgeContract: homeBridge, + web3: homeWeb3, + requiredSignatures: 2, + options: { + from: validator.address, + gas: '4000000' + } + }) + + // Set 2 required signatures for foreign bridge + await setRequiredSignatures({ + bridgeContract: foreignBridge, + web3: foreignWeb3, + requiredSignatures: 2, + options: { + from: validator.address, + gas: '4000000' + } + }) + }) it('should convert eth in home to tokens in foreign', async () => { // check that account has zero tokens in the foreign chain const balance = await token.methods.balanceOf(user.address).call() @@ -109,6 +147,8 @@ describe('native to erc', () => { // empty validator funds await sendAllBalance(homeWeb3, validator.address, secondUser.address) + await sendAllBalance(homeWeb3, secondValidator.address, thirdUser.address) + await sendAllBalance(homeWeb3, thirdValidator.address, fourthUser.address) // send transaction to home chain const depositTx = await homeWeb3.eth.sendTransaction({ @@ -130,14 +170,16 @@ describe('native to erc', () => { assert(originalBalance.eq(balance), "Token balance shouldn't have changed") // send funds back to validator - const sendBalanceBackTx = await sendAllBalance(homeWeb3, secondUser.address, validator.address) + await sendAllBalance(homeWeb3, secondUser.address, validator.address) + await sendAllBalance(homeWeb3, thirdUser.address, secondValidator.address) + const sendBalanceBackTx = await sendAllBalance(homeWeb3, fourthUser.address, thirdValidator.address) // expect Deposit event to be processed await promiseRetry( async retry => { const lastBlockNumber = await homeWeb3.eth.getBlockNumber() // check that a new block was created since the last transaction - if (lastBlockNumber === sendBalanceBackTx.blockNumber + 1) { + if (lastBlockNumber >= sendBalanceBackTx.blockNumber + 1) { await generateNewBlock(homeWeb3, user.address) } else { retry() @@ -165,6 +207,8 @@ describe('native to erc', () => { // empty foreign validator funds await sendAllBalance(foreignWeb3, validator.address, secondUser.address) + await sendAllBalance(foreignWeb3, secondValidator.address, thirdUser.address) + await sendAllBalance(foreignWeb3, thirdValidator.address, fourthUser.address) const foreignBlockNumber = await foreignWeb3.eth.getBlockNumber() // send transaction to home chain @@ -183,7 +227,7 @@ describe('native to erc', () => { await promiseRetry( async retry => { const lastBlockNumber = await homeWeb3.eth.getBlockNumber() - if (lastBlockNumber === lastHomeTx.blockNumber + 1) { + if (lastBlockNumber >= lastHomeTx.blockNumber + 1) { await generateNewBlock(homeWeb3, user.address) } else { retry() @@ -203,6 +247,8 @@ describe('native to erc', () => { // send funds back to validator await sendAllBalance(foreignWeb3, secondUser.address, validator.address) + await sendAllBalance(foreignWeb3, thirdUser.address, secondValidator.address) + await sendAllBalance(foreignWeb3, fourthUser.address, thirdValidator.address) // check that account has tokens in the foreign chain await promiseRetry(async retry => { diff --git a/oracle-e2e/test/utils.js b/oracle-e2e/test/utils.js new file mode 100644 index 000000000..f1b85de02 --- /dev/null +++ b/oracle-e2e/test/utils.js @@ -0,0 +1,12 @@ +const { BRIDGE_VALIDATORS_ABI } = require('../../commons') + +const setRequiredSignatures = async ({ bridgeContract, web3, requiredSignatures, options }) => { + const validatorAddress = await bridgeContract.methods.validatorContract().call() + const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorAddress) + + return validatorContract.methods.setRequiredSignatures(requiredSignatures).send(options) +} + +module.exports = { + setRequiredSignatures +} diff --git a/oracle/Dockerfile b/oracle/Dockerfile index 8e643a0d5..6edc546b3 100644 --- a/oracle/Dockerfile +++ b/oracle/Dockerfile @@ -22,8 +22,6 @@ RUN mv ./contracts/build ./ && rm -rf ./contracts/* ./contracts/.[!.]* && mv ./b COPY ./commons ./commons COPY ./oracle ./oracle -ARG DOT_ENV_PATH=./oracle/.env -COPY ${DOT_ENV_PATH} ./oracle/.env WORKDIR /mono/oracle CMD echo "To start a bridge process run:" \ diff --git a/oracle/docker-compose-erc-native.yml b/oracle/docker-compose-erc-native.yml index fc2ac14ec..6cb838e41 100644 --- a/oracle/docker-compose-erc-native.yml +++ b/oracle/docker-compose-erc-native.yml @@ -40,9 +40,7 @@ services: bridge_transfer: cpus: 0.1 mem_limit: 500m - build: - context: .. - dockerfile: oracle/Dockerfile + image: poanetwork/tokenbridge-oracle:latest env_file: ./.env environment: - NODE_ENV=production @@ -55,9 +53,7 @@ services: bridge_half_duplex_transfer: cpus: 0.1 mem_limit: 500m - build: - context: .. - dockerfile: oracle/Dockerfile + image: poanetwork/tokenbridge-oracle:latest env_file: ./.env environment: - NODE_ENV=production @@ -70,9 +66,7 @@ services: bridge_swap_tokens_worker: cpus: 0.1 mem_limit: 500m - build: - context: .. - dockerfile: oracle/Dockerfile + image: poanetwork/tokenbridge-oracle:latest env_file: ./.env environment: - NODE_ENV=production diff --git a/oracle/docker-compose-transfer.yml b/oracle/docker-compose-transfer.yml index 10180d945..eabba1c32 100644 --- a/oracle/docker-compose-transfer.yml +++ b/oracle/docker-compose-transfer.yml @@ -37,9 +37,7 @@ services: bridge_transfer: cpus: 0.1 mem_limit: 500m - build: - context: .. - dockerfile: oracle/Dockerfile + image: poanetwork/tokenbridge-oracle:latest env_file: ./.env environment: - NODE_ENV=production diff --git a/oracle/docker-compose.yml b/oracle/docker-compose.yml index cded66c7a..73cc6c8df 100644 --- a/oracle/docker-compose.yml +++ b/oracle/docker-compose.yml @@ -32,9 +32,7 @@ services: bridge_request: cpus: 0.1 mem_limit: 500m - build: - context: .. - dockerfile: oracle/Dockerfile + image: poanetwork/tokenbridge-oracle:latest env_file: ./.env environment: - NODE_ENV=production @@ -47,9 +45,7 @@ services: bridge_collected: cpus: 0.1 mem_limit: 500m - build: - context: .. - dockerfile: oracle/Dockerfile + image: poanetwork/tokenbridge-oracle:latest env_file: ./.env environment: - NODE_ENV=production @@ -62,9 +58,7 @@ services: bridge_affirmation: cpus: 0.1 mem_limit: 500m - build: - context: .. - dockerfile: oracle/Dockerfile + image: poanetwork/tokenbridge-oracle:latest env_file: ./.env environment: - NODE_ENV=production @@ -77,9 +71,7 @@ services: bridge_senderhome: cpus: 0.1 mem_limit: 500m - build: - context: .. - dockerfile: oracle/Dockerfile + image: poanetwork/tokenbridge-oracle:latest env_file: ./.env environment: - NODE_ENV=production @@ -92,9 +84,7 @@ services: bridge_senderforeign: cpus: 0.1 mem_limit: 500m - build: - context: .. - dockerfile: oracle/Dockerfile + image: poanetwork/tokenbridge-oracle:latest env_file: ./.env environment: - NODE_ENV=production diff --git a/oracle/src/events/processAMBCollectedSignatures/estimateGas.js b/oracle/src/events/processAMBCollectedSignatures/estimateGas.js index 4168ff672..3fa31676b 100644 --- a/oracle/src/events/processAMBCollectedSignatures/estimateGas.js +++ b/oracle/src/events/processAMBCollectedSignatures/estimateGas.js @@ -46,7 +46,7 @@ async function estimateGas({ // check if all the signatures were made by validators for (let i = 0; i < v.length; i++) { - const address = web3.eth.accounts.recover(message, web3.utils.toHex(v[i]), r[i], s[i]) + const address = web3.eth.accounts.recover(message, `0x${v[i]}`, `0x${r[i]}`, `0x${s[i]}`) logger.debug({ address }, 'Check that signature is from a validator') const isValidator = await validatorContract.methods.isValidator(address).call() diff --git a/oracle/src/events/processAMBCollectedSignatures/index.js b/oracle/src/events/processAMBCollectedSignatures/index.js index 128598132..7b973fb51 100644 --- a/oracle/src/events/processAMBCollectedSignatures/index.js +++ b/oracle/src/events/processAMBCollectedSignatures/index.js @@ -4,7 +4,7 @@ const { HttpListProviderError } = require('http-list-provider') const bridgeValidatorsABI = require('../../../../contracts/build/contracts/BridgeValidators').abi const rootLogger = require('../../services/logger') const { web3Home, web3Foreign } = require('../../services/web3') -const { signatureToVRS, signatureToVRSAMB, packSignatures } = require('../../utils/message') +const { signatureToVRS, packSignatures } = require('../../utils/message') const { parseAMBMessage } = require('../../../../commons') const estimateGas = require('./estimateGas') const { AlreadyProcessedError, IncompatibleContractError, InvalidValidatorError } = require('../../utils/errors') @@ -63,8 +63,7 @@ function processCollectedSignaturesBuilder(config) { v.push(vrs.v) r.push(vrs.r) s.push(vrs.s) - const recover = signatureToVRSAMB(signature) - signaturesArray.push(recover) + signaturesArray.push(vrs) }) await Promise.all(signaturePromises) diff --git a/oracle/src/events/processCollectedSignatures/estimateGas.js b/oracle/src/events/processCollectedSignatures/estimateGas.js index 6c8a215c8..cad273d66 100644 --- a/oracle/src/events/processCollectedSignatures/estimateGas.js +++ b/oracle/src/events/processCollectedSignatures/estimateGas.js @@ -9,9 +9,18 @@ const logger = require('../../services/logger').child({ const web3 = new Web3() const { toBN } = Web3.utils -async function estimateGas({ foreignBridge, validatorContract, message, numberOfCollectedSignatures, v, r, s }) { +async function estimateGas({ + foreignBridge, + validatorContract, + message, + numberOfCollectedSignatures, + v, + r, + s, + signatures +}) { try { - const gasEstimate = await foreignBridge.methods.executeSignatures(v, r, s, message).estimateGas() + const gasEstimate = await foreignBridge.methods.executeSignatures(message, signatures).estimateGas() return gasEstimate } catch (e) { if (e instanceof HttpListProviderError) { @@ -35,7 +44,7 @@ async function estimateGas({ foreignBridge, validatorContract, message, numberOf // check if all the signatures were made by validators for (let i = 0; i < v.length; i++) { - const address = web3.eth.accounts.recover(message, web3.utils.toHex(v[i]), r[i], s[i]) + const address = web3.eth.accounts.recover(message, `0x${v[i]}`, `0x${r[i]}`, `0x${s[i]}`) logger.debug({ address }, 'Check that signature is from a validator') const isValidator = await validatorContract.methods.isValidator(address).call() diff --git a/oracle/src/events/processCollectedSignatures/index.js b/oracle/src/events/processCollectedSignatures/index.js index 1d446de3e..04f6ed80d 100644 --- a/oracle/src/events/processCollectedSignatures/index.js +++ b/oracle/src/events/processCollectedSignatures/index.js @@ -4,7 +4,7 @@ const { HttpListProviderError } = require('http-list-provider') const { BRIDGE_VALIDATORS_ABI } = require('../../../../commons') const rootLogger = require('../../services/logger') const { web3Home, web3Foreign } = require('../../services/web3') -const { signatureToVRS } = require('../../utils/message') +const { signatureToVRS, packSignatures } = require('../../utils/message') const estimateGas = require('./estimateGas') const { AlreadyProcessedError, IncompatibleContractError, InvalidValidatorError } = require('../../utils/errors') const { MAX_CONCURRENT_EVENTS } = require('../../utils/constants') @@ -52,18 +52,21 @@ function processCollectedSignaturesBuilder(config) { requiredSignatures.length = NumberOfCollectedSignatures requiredSignatures.fill(0) + const signaturesArray = [] const [v, r, s] = [[], [], []] logger.debug('Getting message signatures') const signaturePromises = requiredSignatures.map(async (el, index) => { logger.debug({ index }, 'Getting message signature') const signature = await homeBridge.methods.signature(messageHash, index).call() - const recover = signatureToVRS(signature) - v.push(recover.v) - r.push(recover.r) - s.push(recover.s) + const vrs = signatureToVRS(signature) + v.push(vrs.v) + r.push(vrs.r) + s.push(vrs.s) + signaturesArray.push(vrs) }) await Promise.all(signaturePromises) + const signatures = packSignatures(signaturesArray) let gasEstimate try { @@ -74,6 +77,7 @@ function processCollectedSignaturesBuilder(config) { v, r, s, + signatures, message, numberOfCollectedSignatures: NumberOfCollectedSignatures }) @@ -92,7 +96,7 @@ function processCollectedSignaturesBuilder(config) { throw e } } - const data = await foreignBridge.methods.executeSignatures(v, r, s, message).encodeABI() + const data = await foreignBridge.methods.executeSignatures(message, signatures).encodeABI() txToSend.push({ data, gasEstimate, diff --git a/oracle/src/utils/message.js b/oracle/src/utils/message.js index d20359b10..894a47758 100644 --- a/oracle/src/utils/message.js +++ b/oracle/src/utils/message.js @@ -50,17 +50,9 @@ function parseMessage(message) { } } -function signatureToVRS(signature) { - assert.strictEqual(signature.length, 2 + 32 * 2 + 32 * 2 + 2) - signature = strip0x(signature) - const v = parseInt(signature.substr(64 * 2), 16) - const r = `0x${signature.substr(0, 32 * 2)}` - const s = `0x${signature.substr(32 * 2, 32 * 2)}` - return { v, r, s } -} - -function signatureToVRSAMB(rawSignature) { +function signatureToVRS(rawSignature) { const signature = strip0x(rawSignature) + assert.strictEqual(signature.length, 2 + 32 * 2 + 32 * 2) const v = signature.substr(64 * 2) const r = signature.substr(0, 32 * 2) const s = signature.substr(32 * 2, 32 * 2) @@ -85,6 +77,5 @@ module.exports = { createMessage, parseMessage, signatureToVRS, - signatureToVRSAMB, packSignatures } diff --git a/oracle/test/message.test.js b/oracle/test/message.test.js index a07030765..dce8abe05 100644 --- a/oracle/test/message.test.js +++ b/oracle/test/message.test.js @@ -259,9 +259,9 @@ describe('message utils', () => { const { v, r, s } = signatureToVRS(signature) // then - expect(v).to.equal(27) - expect(r).to.equal('0xed157c39b80281741e7d4075655f25b11a9182f12d90878a1ba9bfed111c8996') - expect(s).to.equal('0x20b74dc25ba2f581be753e11673413eb90f1f08285c2100d8e16c6799818c77d') + expect(v).to.equal('1b') + expect(r).to.equal('ed157c39b80281741e7d4075655f25b11a9182f12d90878a1ba9bfed111c8996') + expect(s).to.equal('20b74dc25ba2f581be753e11673413eb90f1f08285c2100d8e16c6799818c77d') }) it('should fail if signature is too short', () => { diff --git a/oracle/test/processCollectedSignatures.test.js b/oracle/test/processCollectedSignatures.test.js index a319c0daf..b40ea359f 100644 --- a/oracle/test/processCollectedSignatures.test.js +++ b/oracle/test/processCollectedSignatures.test.js @@ -2,7 +2,7 @@ const { expect } = require('chai').use(require('chai-as-promised')) const sinon = require('sinon') const Web3 = require('web3') const { HttpListProviderError } = require('http-list-provider') -const { createMessage } = require('../src/utils/message') +const { createMessage, signatureToVRS } = require('../src/utils/message') const estimateGas = require('../src/events/processCollectedSignatures/estimateGas') const errors = require('../src/utils/errors') @@ -116,10 +116,11 @@ describe('processCollectedSignatures', () => { } const message = randomMessage() - const { v, r, s } = web3.eth.accounts.sign( + const { signature } = web3.eth.accounts.sign( message, '0xf41510ea3e58c22cbabe881c9c87e60078dac25b23f93319e355c9ae0562987a' ) + const { v, r, s } = signatureToVRS(signature) // when const result = estimateGas({ @@ -155,10 +156,11 @@ describe('processCollectedSignatures', () => { } const message = randomMessage() - const { v, r, s } = web3.eth.accounts.sign( + const { signature } = web3.eth.accounts.sign( message, '0xf41510ea3e58c22cbabe881c9c87e60078dac25b23f93319e355c9ae0562987a' ) + const { v, r, s } = signatureToVRS(signature) // when const result = estimateGas({ diff --git a/parity/chain-foreign.json b/parity/chain-foreign.json index 67f2cc60c..a3c8ac88f 100644 --- a/parity/chain-foreign.json +++ b/parity/chain-foreign.json @@ -79,6 +79,12 @@ "aaB52d66283F7A1D5978bcFcB55721ACB467384b": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, + "dCC784657C78054aa61FbcFFd2605F32374816A4": { + "balance": "1606938044258990275541962092341162602522202993782792835301376" + }, + "Dcef88209a20D52165230104B245803C3269454d": { + "balance": "1606938044258990275541962092341162602522202993782792835301376" + }, "bb140FbA6242a1c3887A7823F7750a73101383e3": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, diff --git a/parity/chain.json b/parity/chain.json index 586321e3a..ee1b205ed 100644 --- a/parity/chain.json +++ b/parity/chain.json @@ -46,6 +46,8 @@ "0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, "0000000000000000000000000000000000001337": { "balance": "1", "constructor": "0x606060405233600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550670de0b6b3a764000060035534610000575b612904806100666000396000f3006060604052361561013c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306b2ff471461014157806313af40351461018c57806319362a28146101bf5780633f3935d114610248578063432ced04146102b75780634f39ca59146102eb5780636795dbcd1461032457806369fe0e2d146103c857806379ce9fac146103fd5780638da5cb5b1461045557806390b97fc1146104a457806392698814146105245780639890220b1461055d578063ac4e73f914610584578063ac72c12014610612578063c3a358251461064b578063ddca3f43146106c3578063deb931a2146106e6578063df57b74214610747578063e30bd740146107a8578063eadf976014610862578063ef5454d6146108e7578063f25eb5c114610975578063f6d339e414610984575b610000565b3461000057610172600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a1f565b604051808215151515815260200191505060405180910390f35b34610000576101bd600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a81565b005b346100005761022e60048080356000191690602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803560001916906020019091905050610ba2565b604051808215151515815260200191505060405180910390f35b346100005761029d600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610dc9565b604051808215151515815260200191505060405180910390f35b6102d1600480803560001916906020019091905050611035565b604051808215151515815260200191505060405180910390f35b346100005761030a60048080356000191690602001909190505061115f565b604051808215151515815260200191505060405180910390f35b346100005761038660048080356000191690602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050611378565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576103e3600480803590602001909190505061140d565b604051808215151515815260200191505060405180910390f35b346100005761043b60048080356000191690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506114b4565b604051808215151515815260200191505060405180910390f35b34610000576104626115fb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b346100005761050660048080356000191690602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050611621565b60405180826000191660001916815260200191505060405180910390f35b34610000576105436004808035600019169060200190919050506116b2565b604051808215151515815260200191505060405180910390f35b346100005761056a611715565b604051808215151515815260200191505060405180910390f35b34610000576105f8600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611824565b604051808215151515815260200191505060405180910390f35b3461000057610631600480803560001916906020019091905050611d8b565b604051808215151515815260200191505060405180910390f35b34610000576106ad60048080356000191690602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050611dee565b6040518082815260200191505060405180910390f35b34610000576106d0611e83565b6040518082815260200191505060405180910390f35b3461000057610705600480803560001916906020019091905050611e89565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3461000057610766600480803560001916906020019091905050611ed2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576107d9600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611f1b565b6040518080602001828103825283818151815260200191508051906020019080838360008314610828575b80518252602083111561082857602082019150602081019050602083039250610804565b505050905090810190601f1680156108545780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576108cd60048080356000191690602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803590602001909190505061200c565b604051808215151515815260200191505060405180910390f35b346100005761095b600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050612236565b604051808215151515815260200191505060405180910390f35b3461000057610982612425565b005b3461000057610a0560048080356000191690602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050612698565b604051808215151515815260200191505060405180910390f35b60006000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805460018160011615610100020316600290049050141590505b919050565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610add57610b9f565b8073ffffffffffffffffffffffffffffffffffffffff16600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236460405180905060405180910390a380600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b50565b6000833373ffffffffffffffffffffffffffffffffffffffff1660016000836000191660001916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141515610c1d57610dc1565b82600160008760001916600019168152602001908152602001600020600201856040518082805190602001908083835b60208310610c705780518252602082019150602081019050602083039250610c4d565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208160001916905550836040518082805190602001908083835b60208310610cdf5780518252602082019150602081019050602083039250610cbc565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902085600019167fb829c3e412537bbe794c048ccb9e4605bb4aaaa8e4d4c15c1a6e0c2adc1716ea866040518080602001828103825283818151815260200191508051906020019080838360008314610d82575b805182526020831115610d8257602082019150602081019050602083039250610d5e565b505050905090810190601f168015610dae5780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600191505b5b509392505050565b6000813373ffffffffffffffffffffffffffffffffffffffff1660016000836040518082805190602001908083835b60208310610e1b5780518252602082019150602081019050602083039250610df8565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141515610ea45761102f565b82600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610f2d57805160ff1916838001178555610f5b565b82800160010185558215610f5b579182015b82811115610f5a578251825591602001919060010190610f3f565b5b509050610f8091905b80821115610f7c576000816000905550600101610f64565b5090565b50503373ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b60208310610fcd5780518252602082019150602081019050602083039250610faa565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390207f098ae8581bb8bd9af1beaf7f2e9f51f31a8e5a8bfada4e303a645d71d9c9192060405180905060405180910390a3600191505b5b50919050565b600081600060016000836000191660001916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561109b57611159565b6003543410156110aa57611158565b3360016000856000191660001916815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff1683600019167f4963513eca575aba66fdcd25f267aae85958fe6fb97e75fa25d783f1a091a22160405180905060405180910390a3600191505b5b5b50919050565b6000813373ffffffffffffffffffffffffffffffffffffffff1660016000836000191660001916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156111da57611372565b6002600060016000866000191660001916815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805460018160011615610100020316600290046000825580601f1061127c57506112b3565b601f0160209004906000526020600020908101906112b291905b808211156112ae576000816000905550600101611296565b5090565b5b5060016000846000191660001916815260200190815260200160002060006000820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550503373ffffffffffffffffffffffffffffffffffffffff1683600019167fef1961b4d2909dc23643b309bfe5c3e5646842d98c3a58517037ef3871185af360405180905060405180910390a3600191505b5b50919050565b6000600160008460001916600019168152602001908152602001600020600201826040518082805190602001908083835b602083106113cc57805182526020820191506020810190506020830392506113a9565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020546001900490505b92915050565b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561146b576114af565b816003819055507f6bbc57480a46553fa4d156ce702beef5f3ad66303b0ed1a5d4cb44966c6584c3826040518082815260200191505060405180910390a1600190505b5b919050565b6000823373ffffffffffffffffffffffffffffffffffffffff1660016000836000191660001916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561152f576115f4565b8260016000866000191660001916815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1685600019167f7b97c62130aa09acbbcbf7482630e756592496f1759eaf702f469cf64dfb779460405180905060405180910390a4600191505b5b5092915050565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600160008460001916600019168152602001908152602001600020600201826040518082805190602001908083835b602083106116755780518252602082019150602081019050602083039250611652565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390205490505b92915050565b6000600060016000846000191660001916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141590505b919050565b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561177357611821565b7fdef931299fe61d176f949118058530c1f3f539dcb6950b4e372c9b835c33ca073073ffffffffffffffffffffffffffffffffffffffff16316040518082815260200191505060405180910390a13373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051809050600060405180830381858888f19350505050151561181b57610000565b600190505b5b90565b60006000836040518082805190602001908083835b6020831061185c5780518252602082019150602081019050602083039250611839565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390203373ffffffffffffffffffffffffffffffffffffffff1660016000836000191660001916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561190157611d83565b846040518082805190602001908083835b602083106119355780518252602082019150602081019050602083039250611912565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209150600060016000846000191660001916815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614158015611ab4575081600019166002600060016000866000191660001916815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518082805460018160011615610100020316600290048015611aa15780601f10611a7f576101008083540402835291820191611aa1565b820191906000526020600020905b815481529060010190602001808311611a8d575b5050915050604051809103902060001916145b15611c79576002600060016000856000191660001916815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805460018160011615610100020316600290046000825580601f10611b5b5750611b92565b601f016020900490600052602060002090810190611b9191905b80821115611b8d576000816000905550600101611b75565b5090565b5b5060016000836000191660001916815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16856040518082805190602001908083835b60208310611c1c5780518252602082019150602081019050602083039250611bf9565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390207f12491ad95fd945e444d88a894ffad3c21959880a4dcd8af99d4ae4ffc71d4abd60405180905060405180910390a35b8360016000846000191660001916815260200190815260200160002060010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff16856040518082805190602001908083835b60208310611d215780518252602082019150602081019050602083039250611cfe565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390207f728435a0031f6a04538fcdd24922a7e06bc7bc945db03e83d22122d1bc5f28df60405180905060405180910390a3600192505b5b505092915050565b6000600060016000846000191660001916815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141590505b919050565b6000600160008460001916600019168152602001908152602001600020600201826040518082805190602001908083835b60208310611e425780518252602082019150602081019050602083039250611e1f565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020546001900490505b92915050565b60035481565b600060016000836000191660001916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b919050565b600060016000836000191660001916815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b919050565b6020604051908101604052806000815250600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015611fff5780601f10611fd457610100808354040283529160200191611fff565b820191906000526020600020905b815481529060010190602001808311611fe257829003601f168201915b505050505090505b919050565b6000833373ffffffffffffffffffffffffffffffffffffffff1660016000836000191660001916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156120875761222e565b82600102600160008760001916600019168152602001908152602001600020600201856040518082805190602001908083835b602083106120dd57805182526020820191506020810190506020830392506120ba565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208160001916905550836040518082805190602001908083835b6020831061214c5780518252602082019150602081019050602083039250612129565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902085600019167fb829c3e412537bbe794c048ccb9e4605bb4aaaa8e4d4c15c1a6e0c2adc1716ea8660405180806020018281038252838181518152602001915080519060200190808383600083146121ef575b8051825260208311156121ef576020820191506020810190506020830392506121cb565b505050905090810190601f16801561221b5780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600191505b5b509392505050565b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156122945761241f565b82600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061231d57805160ff191683800117855561234b565b8280016001018555821561234b579182015b8281111561234a57825182559160200191906001019061232f565b5b50905061237091905b8082111561236c576000816000905550600101612354565b5090565b50508173ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b602083106123bd578051825260208201915060208101905060208303925061239a565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390207f098ae8581bb8bd9af1beaf7f2e9f51f31a8e5a8bfada4e303a645d71d9c9192060405180905060405180910390a3600190505b5b92915050565b3373ffffffffffffffffffffffffffffffffffffffff16600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180828054600181600116156101000203166002900480156124d65780601f106124b45761010080835404028352918201916124d6565b820191906000526020600020905b8154815290600101906020018083116124c2575b505091505060405180910390207f12491ad95fd945e444d88a894ffad3c21959880a4dcd8af99d4ae4ffc71d4abd60405180905060405180910390a360016000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180828054600181600116156101000203166002900480156125b05780601f1061258e5761010080835404028352918201916125b0565b820191906000526020600020905b81548152906001019060200180831161259c575b505091505060405180910390206000191660001916815260200190815260200160002060010160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805460018160011615610100020316600290046000825580601f1061265d5750612694565b601f01602090049060005260206000209081019061269391905b8082111561268f576000816000905550600101612677565b5090565b5b505b565b6000833373ffffffffffffffffffffffffffffffffffffffff1660016000836000191660001916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141515612713576128d0565b8273ffffffffffffffffffffffffffffffffffffffff16600102600160008760001916600019168152602001908152602001600020600201856040518082805190602001908083835b6020831061277f578051825260208201915060208101905060208303925061275c565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208160001916905550836040518082805190602001908083835b602083106127ee57805182526020820191506020810190506020830392506127cb565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902085600019167fb829c3e412537bbe794c048ccb9e4605bb4aaaa8e4d4c15c1a6e0c2adc1716ea866040518080602001828103825283818151815260200191508051906020019080838360008314612891575b8051825260208311156128915760208201915060208101905060208303925061286d565b505050905090810190601f1680156128bd5780820380516001836020036101000a031916815260200191505b509250505060405180910390a3600191505b5b5093925050505600a165627a7a7230582066b2da4773a0f1d81efe071c66b51c46868a871661efd18c0f629353ff4c1f9b0029" }, "aaB52d66283F7A1D5978bcFcB55721ACB467384b": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, + "dCC784657C78054aa61FbcFFd2605F32374816A4": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, + "Dcef88209a20D52165230104B245803C3269454d": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "bb140FbA6242a1c3887A7823F7750a73101383e3": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "7FC1442AB55Da569940Eb750AaD2BAA63DA4010E": { "balance": "500000000000000000000" }, "B4579fd5AfEaB60B03Db3F408AAdD315035943f7": { "balance": "500000000000000000000" }