diff --git a/deployment-e2e/molecule/ultimate-erc-to-native/molecule.yml b/deployment-e2e/molecule/ultimate-erc-to-native/molecule.yml index be847d6c8..cab9437be 100644 --- a/deployment-e2e/molecule/ultimate-erc-to-native/molecule.yml +++ b/deployment-e2e/molecule/ultimate-erc-to-native/molecule.yml @@ -36,6 +36,8 @@ provisioner: COMMON_FOREIGN_RPC_URL: "http://parity2:8545" ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b" ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9" + ORACLE_HOME_START_BLOCK: 1 + ORACLE_FOREIGN_START_BLOCK: 1 ui-erc-to-native-host: COMMON_HOME_RPC_URL: "http://localhost:8541" COMMON_FOREIGN_RPC_URL: "http://localhost:8542" diff --git a/deployment/roles/oracle/tasks/logging.yml b/deployment/roles/oracle/tasks/logging.yml index eade57df6..04412d17c 100644 --- a/deployment/roles/oracle/tasks/logging.yml +++ b/deployment/roles/oracle/tasks/logging.yml @@ -18,6 +18,25 @@ content: "{{ docker_compose_parsed | to_yaml }}" dest: "{{ bridge_path }}/oracle/docker-compose.yml" +- name: Slurp docker compose extended file + slurp: + src: "{{ bridge_path }}/oracle/docker-compose-transfer.yml" + register: docker_compose_extended_slurp + +- name: Parse docker compose extended file + set_fact: + docker_compose_extended_parsed: "{{ docker_compose_extended_slurp['content'] | b64decode | from_yaml }}" + +- name: Set logger to remote server for extended file + set_fact: + docker_compose_extended_parsed: "{{ docker_compose_extended_parsed |combine({'services': {item: {'logging': {'driver': 'syslog','options': {'tag': '{{.Name}}/{{.ID}}'}}}}}, recursive=True) }}" + with_items: "{{ docker_compose_extended_parsed.services }}" + +- name: Write new docker-compose-extended file + copy: + content: "{{ docker_compose_extended_parsed | to_yaml }}" + dest: "{{ bridge_path }}/oracle/docker-compose-transfer.yml" + - name: Set the local container logs configuration file template: src: 31-oracle-docker.conf.j2 diff --git a/deployment/roles/oracle/tasks/post_config.yml b/deployment/roles/oracle/tasks/post_config.yml index 1ba073649..f4b635fe9 100644 --- a/deployment/roles/oracle/tasks/post_config.yml +++ b/deployment/roles/oracle/tasks/post_config.yml @@ -5,14 +5,16 @@ 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: | - HOME_START_BLOCK={{ (BLOCKS.stdout | from_json).homeStartBlock }} - FOREIGN_START_BLOCK={{ (BLOCKS.stdout | from_json).foreignStartBlock }} + 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: Get validator address become_user: "{{ compose_service_user }}" diff --git a/deployment/roles/oracle/templates/.env.j2 b/deployment/roles/oracle/templates/.env.j2 index 67ad1f730..f5c403ca2 100644 --- a/deployment/roles/oracle/templates/.env.j2 +++ b/deployment/roles/oracle/templates/.env.j2 @@ -1,6 +1,8 @@ ## 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 }} @@ -45,3 +47,10 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }} 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_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/e2e-commons/components-envs/monitor-amb.env b/e2e-commons/components-envs/monitor-amb.env new file mode 100644 index 000000000..c866ec926 --- /dev/null +++ b/e2e-commons/components-envs/monitor-amb.env @@ -0,0 +1,18 @@ +COMMON_HOME_RPC_URL=http://parity1:8545 +COMMON_FOREIGN_RPC_URL=http://parity2:8545 +COMMON_HOME_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0 +COMMON_FOREIGN_BRIDGE_ADDRESS=0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0 +MONITOR_HOME_START_BLOCK=0 +MONITOR_FOREIGN_START_BLOCK=0 +MONITOR_VALIDATOR_HOME_TX_LIMIT=300000 +COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/ +COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard +COMMON_HOME_GAS_PRICE_FALLBACK=1000000000 +COMMON_HOME_GAS_PRICE_FACTOR=1 +MONITOR_VALIDATOR_FOREIGN_TX_LIMIT=300000 +COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/ +COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard +COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000 +COMMON_FOREIGN_GAS_PRICE_FACTOR=1 +MONITOR_TX_NUMBER_THRESHOLD=100 +MONITOR_PORT=3013 diff --git a/e2e-commons/components-envs/oracle-erc20-native.env b/e2e-commons/components-envs/oracle-erc20-native.env index 7f832b068..13f773f20 100644 --- a/e2e-commons/components-envs/oracle-erc20-native.env +++ b/e2e-commons/components-envs/oracle-erc20-native.env @@ -21,3 +21,5 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR=0.1 ORACLE_HOME_RPC_POLLING_INTERVAL=500 ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500 ORACLE_ALLOW_HTTP_FOR_RPC=yes +ORACLE_HOME_START_BLOCK=1 +ORACLE_FOREIGN_START_BLOCK=1 diff --git a/e2e-commons/constants.json b/e2e-commons/constants.json index a8fc19fc5..cd63c80df 100644 --- a/e2e-commons/constants.json +++ b/e2e-commons/constants.json @@ -41,7 +41,8 @@ "home": "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0", "foreign": "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0", "homeBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1", - "foreignBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1" + "foreignBox": "0x6C4EaAb8756d53Bf599FFe2347FAFF1123D6C8A1", + "monitor": "http://monitor-amb:3013" }, "homeRPC": { "URL": "http://parity1:8545", diff --git a/e2e-commons/docker-compose.yml b/e2e-commons/docker-compose.yml index f4fe59d4a..722af57c0 100644 --- a/e2e-commons/docker-compose.yml +++ b/e2e-commons/docker-compose.yml @@ -132,6 +132,17 @@ services: - "3012:3012" networks: - ultimate + monitor-amb: + build: + context: .. + dockerfile: monitor/Dockerfile + args: + DOT_ENV_PATH: e2e-commons/components-envs/monitor-amb.env + entrypoint: yarn check-and-start + ports: + - "3013:3013" + networks: + - ultimate e2e: build: context: .. diff --git a/e2e-commons/up.sh b/e2e-commons/up.sh index 246cd8e5a..86563fc87 100755 --- a/e2e-commons/up.sh +++ b/e2e-commons/up.sh @@ -46,7 +46,7 @@ while [ "$1" != "" ]; do fi if [ "$1" == "monitor" ]; then - docker-compose up -d monitor monitor-erc20 monitor-erc20-native + docker-compose up -d monitor monitor-erc20 monitor-erc20-native monitor-amb fi if [ "$1" == "native-to-erc" ]; then diff --git a/monitor-e2e/periodically-check-all.sh b/monitor-e2e/periodically-check-all.sh index 6ec79044b..fb494cffa 100755 --- a/monitor-e2e/periodically-check-all.sh +++ b/monitor-e2e/periodically-check-all.sh @@ -3,4 +3,5 @@ while true; do docker-compose -f ../e2e-commons/docker-compose.yml exec monitor yarn check-all docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20 yarn check-all docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20-native yarn check-all + docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-amb yarn check-all done diff --git a/monitor-e2e/test/amb.js b/monitor-e2e/test/amb.js new file mode 100644 index 000000000..59b22fe54 --- /dev/null +++ b/monitor-e2e/test/amb.js @@ -0,0 +1,128 @@ +const assert = require('assert') +const axios = require('axios') +const { amb, user, foreignRPC, homeRPC, validator } = require('../../e2e-commons/constants.json') +const { waitUntil, sendAMBMessage, addValidator } = require('../utils') + +const baseUrl = amb.monitor + +describe('AMB', () => { + describe('balances', async () => { + let data + + before(async () => { + ;({ data } = await axios.get(`${baseUrl}`)) + }) + + describe('home', async () => { + it('should contain toForeign:', () => assert(data.home.toForeign === 0)) + it('should contain fromForeign', () => assert(data.home.fromForeign === 0)) + }) + + describe('foreign', async () => { + it('should contain fromHome:', () => assert(data.foreign.fromHome === 0)) + it('should contain toHome', () => assert(data.foreign.toHome === 0)) + }) + + describe('general', async () => { + it('should contain fromHomeToForeignDiff', () => assert(data.fromHomeToForeignDiff === 0)) + it('should contain fromForeignToHomeDiff', () => assert(data.fromForeignToHomeDiff === 0)) + it('should contain lastChecked', () => assert(data.lastChecked >= 0)) + it('should contain timeDiff', () => assert(data.timeDiff >= 0)) + it('should contain lastChecked', () => assert(data.lastChecked >= 0)) + }) + }) + describe('validators', async () => { + let data + + before(async () => { + ;({ data } = await axios.get(`${baseUrl}/validators`)) + }) + + it('home', () => { + assert(typeof data.home.validators === 'object') + assert(data.home.validators[validator.address].balance > 0) + assert(data.home.validators[validator.address].leftTx > 0) + assert(data.home.validators[validator.address].gasPrice > 0) + }) + + it('foreign', () => { + assert(typeof data.foreign.validators === 'object') + assert(data.foreign.validators[validator.address].balance > 0) + assert(data.foreign.validators[validator.address].leftTx > 0) + assert(data.foreign.validators[validator.address].gasPrice > 0) + }) + + it('requiredSignaturesMatch', () => assert(data.requiredSignaturesMatch, 1)) + it('validatorsMatch', () => assert(data.validatorsMatch)) + it('lastChecked', () => assert(data.lastChecked >= 0)) + it('timeDiff', () => assert(data.timeDiff >= 0)) + it('homeOk', () => assert(data.homeOk)) + it('foreignOk', () => assert(data.foreignOk)) + it('ok', () => assert(data.ok)) + }) + describe('eventsStats', async () => { + let data + + before(async () => { + ;({ data } = await axios.get(`${baseUrl}/eventsStats`)) + }) + + it('ok', () => assert(data.ok)) + it('lastChecked', () => assert(data.lastChecked >= 0)) + it('timeDiff', () => assert(data.timeDiff >= 0)) + it('home-deliveredMsgNotProcessedInForeign', () => + assert(typeof data.home.deliveredMsgNotProcessedInForeign === 'object')) + it('home-processedMsgNotDeliveredInForeign', () => + assert(typeof data.home.processedMsgNotDeliveredInForeign === 'object')) + it('foreign-deliveredMsgNotProcessedInHome', () => + assert(typeof data.foreign.deliveredMsgNotProcessedInHome === 'object')) + it('foreign-processedMsgNotDeliveredInHome', () => + assert(typeof data.foreign.processedMsgNotDeliveredInHome === 'object')) + }) + describe('alerts', async () => { + let data + + before(async () => { + ;({ data } = await axios.get(`${baseUrl}/alerts`)) + }) + + it('ok', () => assert(data.ok)) + it('lastChecked', () => assert(data.lastChecked >= 0)) + it('timeDiff', () => assert(data.timeDiff >= 0)) + it('executeSignatures', () => assert(typeof data.executeSignatures === 'object')) + it('executeAffirmations', () => assert(typeof data.executeAffirmations === 'object')) + }) + describe('changing state of contracts', () => { + let data + + before(async () => { + assert((await axios.get(`${baseUrl}/validators`)).data.validatorsMatch === true) + }) + + it('should change fromForeignToHomeDiff', async () => { + // send message + await sendAMBMessage(foreignRPC.URL, user, amb.foreignBox, amb.foreign, amb.homeBox) + + await waitUntil(async () => { + ;({ data } = await axios.get(`${baseUrl}`)) + return data.fromForeignToHomeDiff !== 0 + }) + }) + it('should change fromHomeToForeignDiff', async () => { + // send message + await sendAMBMessage(homeRPC.URL, user, amb.homeBox, amb.home, amb.foreignBox) + + await waitUntil(async () => { + ;({ data } = await axios.get(`${baseUrl}`)) + return data.fromHomeToForeignDiff !== 0 + }) + }) + it('should change validatorsMatch', async () => { + await addValidator(foreignRPC.URL, validator, amb.foreign) + await waitUntil(async () => { + ;({ data } = await axios.get(`${baseUrl}/validators`)) + return data.validatorsMatch === false + }) + }) + }) +}) diff --git a/monitor-e2e/utils.js b/monitor-e2e/utils.js index eaa0d8b04..0b26fc8d1 100644 --- a/monitor-e2e/utils.js +++ b/monitor-e2e/utils.js @@ -1,5 +1,5 @@ const Web3 = require('web3') -const { ERC677_BRIDGE_TOKEN_ABI, BRIDGE_VALIDATORS_ABI, FOREIGN_NATIVE_TO_ERC_ABI } = require('../commons') +const { ERC677_BRIDGE_TOKEN_ABI, BRIDGE_VALIDATORS_ABI, FOREIGN_NATIVE_TO_ERC_ABI, BOX_ABI } = require('../commons') const waitUntil = async (predicate, step = 100, timeout = 10000) => { const stopTime = Date.now() + timeout @@ -37,6 +37,17 @@ const sendTokens = async (rpcUrl, account, tokenAddress, recipientAddress) => { }) } +const sendAMBMessage = async (rpcUrl, account, boxAddress, bridgeAddress, boxOtherSideAddress) => { + const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl)) + web3.eth.accounts.wallet.add(account.privateKey) + const homeBox = new web3.eth.Contract(BOX_ABI, boxAddress) + + await homeBox.methods.setValueOnOtherNetwork(3, bridgeAddress, boxOtherSideAddress).send({ + from: account.address, + gas: '400000' + }) +} + const addValidator = async (rpcUrl, account, bridgeAddress) => { const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl)) web3.eth.accounts.wallet.add(account.privateKey) @@ -53,5 +64,6 @@ module.exports = { waitUntil, sendEther, sendTokens, - addValidator + addValidator, + sendAMBMessage } diff --git a/monitor-e2e/wait-for-monitor.sh b/monitor-e2e/wait-for-monitor.sh index 52810e81a..4fd2ef7e4 100755 --- a/monitor-e2e/wait-for-monitor.sh +++ b/monitor-e2e/wait-for-monitor.sh @@ -7,6 +7,7 @@ check_files_exist() { (docker-compose -f ../e2e-commons/docker-compose.yml exec monitor /bin/bash -c "$command") || rc=1 (docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20 /bin/bash -c "$command") || rc=1 (docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-erc20-native /bin/bash -c "$command") || rc=1 + (docker-compose -f ../e2e-commons/docker-compose.yml exec monitor-amb /bin/bash -c "$command") || rc=1 done return $rc } diff --git a/monitor/crontab.example b/monitor/crontab.example index 1c57e68c3..4c368b3dc 100644 --- a/monitor/crontab.example +++ b/monitor/crontab.example @@ -1,5 +1,5 @@ # Yarn: -*/4 * * * * cd $HOME/bridge-monitor; yarn check-all >>cronWorker.out 2>>cronWorker.err +*/4 * * * * cd $HOME/tokenbridge/monitor; yarn check-all >>cronWorker.out 2>>cronWorker.err # Docker: -*/4 * * * * cd $HOME/bridge-monitor; docker-compose exec monitor yarn check-all >>cronWorker.out 2>>cronWorker.err +*/4 * * * * cd $HOME/tokenbridge/monitor; docker-compose exec monitor yarn check-all >>cronWorker.out 2>>cronWorker.err diff --git a/monitor/index.js b/monitor/index.js index ebf211ef9..50ff5426c 100644 --- a/monitor/index.js +++ b/monitor/index.js @@ -77,10 +77,10 @@ app.get('/eventsStats', async (req, res, next) => { try { const results = await readFile('./responses/eventsStats.json') results.ok = - results.onlyInHomeDeposits.length === 0 && - results.onlyInForeignDeposits.length === 0 && - results.onlyInHomeWithdrawals.length === 0 && - results.onlyInForeignWithdrawals.length === 0 + (results.onlyInHomeDeposits || results.home.deliveredMsgNotProcessedInForeign).length === 0 && + (results.onlyInForeignDeposits || results.home.processedMsgNotDeliveredInForeign).length === 0 && + (results.onlyInHomeWithdrawals || results.foreign.deliveredMsgNotProcessedInHome).length === 0 && + (results.onlyInForeignWithdrawals || results.foreign.processedMsgNotDeliveredInHome).length === 0 res.json(results) } catch (e) { // this will eventually be handled by your error handling middleware