diff --git a/alm-e2e/run-tests.sh b/alm-e2e/run-tests.sh index e73464d1..fd2a6bd9 100755 --- a/alm-e2e/run-tests.sh +++ b/alm-e2e/run-tests.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash cd $(dirname $0) -../e2e-commons/up.sh deploy blocks alm alm-e2e +../e2e-commons/up.sh deploy generate-amb-tx blocks alm alm-e2e # run oracle amb e2e tests to generate transactions for alm docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run alm diff --git a/alm-e2e/src/test.js b/alm-e2e/src/test.js index e35d3986..d02f94dd 100644 --- a/alm-e2e/src/test.js +++ b/alm-e2e/src/test.js @@ -6,8 +6,8 @@ jest.setTimeout(60000) const statusText = 'Success' const statusSelector = 'label[data-id="status"]' -const homeToForeignTxURL = 'http://localhost:3004/77/0xbc83d43bdc675a615a2b820e43e52d25857aa5fdd77acf2dd92cd247af2c693c' -const foreignToHomeTxURL = 'http://localhost:3004/42/0x09dfb947dbd17e27bcc117773b6e133829f7cef9646199a93ef019c4f7c0fec6' +const homeToForeignTxURL = 'http://localhost:3004/77/0x295efbe6ae98937ef35d939376c9bd752b4dc6f6899a9d5ddd6a57cea3d76c89' +const foreignToHomeTxURL = 'http://localhost:3004/42/0x7262f7dbe6c30599edded2137fbbe93c271b37f5c54dd27f713f0cf510e3b4dd' describe('ALM', () => { let browser diff --git a/e2e-commons/constants.json b/e2e-commons/constants.json index 14b0b36a..9eb9bced 100644 --- a/e2e-commons/constants.json +++ b/e2e-commons/constants.json @@ -49,6 +49,12 @@ "blockedHomeBox": "0xF9698Eb93702dfdd0e2d802088d4c21822a8A977", "monitor": "http://monitor-amb:3013/bridge" }, + "amb2": { + "home": "0x5A42E119990c3F3A80Fea20aAF4c3Ff4DB240Cc9", + "foreign": "0x897527391ad3837604973d78D3514f44c36AB9FC", + "homeBox": "0xb008E9076fCbDB2C3AF84225Bc07Eb35B2bE5ECD", + "foreignBox": "0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127" + }, "homeRPC": { "URL": "http://parity1:8545", "ID": "77" diff --git a/e2e-commons/scripts/deploy.sh b/e2e-commons/scripts/deploy.sh index e5f1742d..26b7e4af 100755 --- a/e2e-commons/scripts/deploy.sh +++ b/e2e-commons/scripts/deploy.sh @@ -35,3 +35,9 @@ echo -e "\n\n############ Deploying one more test contract for amb ############\ cd "$DEPLOY_PATH" node src/utils/deployTestBox.js cd - > /dev/null + +echo -e "\n\n############ Deploying one more amb without oracle for confirm relay tests ############\n" +cp "$ENVS_PATH/amb.env" "$DEPLOY_PATH/.env" +cd "$DEPLOY_PATH" +node deploy.js +cd - > /dev/null diff --git a/e2e-commons/up.sh b/e2e-commons/up.sh index b3813379..8f7063ae 100755 --- a/e2e-commons/up.sh +++ b/e2e-commons/up.sh @@ -93,5 +93,25 @@ while [ "$1" != "" ]; do startValidator "-p validator3" "$oracle3Values" redis3 rabbit3 fi + if [ "$1" == "generate-amb-tx" ]; then + docker-compose run e2e yarn workspace oracle-e2e run generate-amb-tx + fi + + if [ "$1" == "manual-amb-relay" ]; then + env="-e COMMON_HOME_BRIDGE_ADDRESS=0x5A42E119990c3F3A80Fea20aAF4c3Ff4DB240Cc9 -e COMMON_FOREIGN_BRIDGE_ADDRESS=0x897527391ad3837604973d78D3514f44c36AB9FC" + # these tx hash are hardcoded and need to be updated manually + # once e2e environment setup process is changed + echo '0xea625a823bc5018dc3a4efe349f623e5ebb8c987b55f44d50d6556f42af9a400' > txHashes.txt + docker-compose -p validator1 run -v $(pwd)/txHashes.txt:/tmp/txHashes.txt $env oracle-amb yarn confirm:affirmation-request \ + /tmp/txHashes.txt \ + 0x031c42e44485002c9215a5b1b75e9516131485ce29884a58765bf7a0038538f9 + docker-compose -p validator1 run $env oracle-amb yarn confirm:signature-request \ + 0x1506a18af91afe732167ccbc178b55fc2547da4a814d13c015b6f496cf171754 | tee .tmp.log + tx_hash=$(cat .tmp.log | grep generatedTransactionHash | jq -r .generatedTransactionHash) + rm .tmp.log + rm txHashes.txt + docker-compose -p validator1 run $env oracle-amb yarn confirm:collected-signatures $tx_hash + fi + shift # Shift all the parameters down by one done diff --git a/oracle-e2e/package.json b/oracle-e2e/package.json index 03f0765b..0885d858 100644 --- a/oracle-e2e/package.json +++ b/oracle-e2e/package.json @@ -5,6 +5,7 @@ "main": "index.js", "scripts": { "start": "mocha", + "generate-amb-tx": "node ./scripts/generate-amb-tx.js", "lint": "eslint . --ignore-path ../.eslintignore", "amb": "mocha test/amb.js", "erc-to-native": "mocha test/ercToNative.js", diff --git a/oracle-e2e/run-tests.sh b/oracle-e2e/run-tests.sh index fe05556e..a565a256 100755 --- a/oracle-e2e/run-tests.sh +++ b/oracle-e2e/run-tests.sh @@ -10,7 +10,7 @@ case "$mode" in ;; esac -MODE="$mode" ../e2e-commons/up.sh deploy blocks oracle oracle-validator-2 oracle-validator-3 +MODE="$mode" ../e2e-commons/up.sh deploy generate-amb-tx manual-amb-relay blocks oracle oracle-validator-2 oracle-validator-3 docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run start $script rc=$? diff --git a/oracle-e2e/scripts/generate-amb-tx.js b/oracle-e2e/scripts/generate-amb-tx.js new file mode 100644 index 00000000..5b617499 --- /dev/null +++ b/oracle-e2e/scripts/generate-amb-tx.js @@ -0,0 +1,29 @@ +const Web3 = require('web3') +const { user, homeRPC, foreignRPC, amb2: amb } = require('../../e2e-commons/constants.json') +const { BOX_ABI } = require('../../commons') + +const homeWeb3 = new Web3(new Web3.providers.HttpProvider(homeRPC.URL)) +const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(foreignRPC.URL)) + +homeWeb3.eth.accounts.wallet.add(user.privateKey) +foreignWeb3.eth.accounts.wallet.add(user.privateKey) + +const opts = { + from: user.address, + gas: 400000, + gasPrice: '1' +} +const homeBox = new homeWeb3.eth.Contract(BOX_ABI, amb.homeBox, opts) +const foreignBox = new foreignWeb3.eth.Contract(BOX_ABI, amb.foreignBox, opts) + +async function main() { + const res1 = await homeBox.methods.setValueOnOtherNetwork(123, amb.home, amb.foreignBox).send() + const res2 = await foreignBox.methods.setValueOnOtherNetwork(456, amb.foreign, amb.homeBox).send() + const res3 = await foreignBox.methods.setValueOnOtherNetwork(789, amb.foreign, amb.homeBox).send() + + console.log(res1.transactionHash) + console.log(res2.transactionHash) + console.log(res3.transactionHash) +} + +main() diff --git a/oracle-e2e/test/amb.js b/oracle-e2e/test/amb.js index b61d8ab5..1b614c73 100644 --- a/oracle-e2e/test/amb.js +++ b/oracle-e2e/test/amb.js @@ -63,6 +63,17 @@ describe('arbitrary message bridging', () => { } }) }) + describe('Confirm Relay', () => { + it('should process lost affirmation-request via confirm relay', async () => { + const value = await homeBox.methods.value().call() + assert(value === '789', 'incorrect value') + }) + + it('should process lost signature-request & collected-signatures via confirm relay', async () => { + const value = await foreignBox.methods.value().call() + assert(value === '123', 'incorrect value') + }) + }) describe('Home to Foreign', () => { describe('Subsidized Mode', () => { it('should bridge message', async () => { @@ -71,12 +82,13 @@ describe('arbitrary message bridging', () => { const initialValue = await foreignBox.methods.value().call() assert(!toBN(initialValue).eq(toBN(newValue)), 'initial value should be different from new value') - await homeBox.methods + const res = await homeBox.methods .setValueOnOtherNetwork(newValue, amb.home, amb.foreignBox) .send() .catch(e => { console.error(e) }) + console.log(res.transactionHash) // check that value changed and balance decreased await uniformRetry(async retry => { @@ -169,12 +181,13 @@ describe('arbitrary message bridging', () => { const initialValue = await homeBox.methods.value().call() assert(!toBN(initialValue).eq(toBN(newValue)), 'initial value should be different from new value') - await foreignBox.methods + const res = await foreignBox.methods .setValueOnOtherNetwork(newValue, amb.foreign, amb.homeBox) .send() .catch(e => { console.error(e) }) + console.log(res.transactionHash) // check that value changed and balance decreased await uniformRetry(async retry => { @@ -268,7 +281,7 @@ describe('arbitrary message bridging', () => { const selector = homeWeb3.utils.soliditySha3('eth_call(address,bytes,uint256)') const data1 = homeWeb3.eth.abi.encodeParameters( ['address', 'bytes', 'uint256'], - [amb.foreignBox, foreignBox.methods.value().encodeABI(), 60] + [amb.foreignBox, foreignBox.methods.value().encodeABI(), 25] ) const data2 = homeWeb3.eth.abi.encodeParameters( ['address', 'bytes', 'uint256'], @@ -446,7 +459,7 @@ describe('arbitrary message bridging', () => { }) it('should make async eth_getTransactionByHash', async () => { - const txHash = '0x09dfb947dbd17e27bcc117773b6e133829f7cef9646199a93ef019c4f7c0fec6' + const txHash = '0x7262f7dbe6c30599edded2137fbbe93c271b37f5c54dd27f713f0cf510e3b4dd' const tx = await foreignWeb3.eth.getTransaction(txHash) const selector = homeWeb3.utils.soliditySha3('eth_getTransactionByHash(bytes32)') @@ -479,7 +492,7 @@ describe('arbitrary message bridging', () => { }) it('should make async eth_getTransactionReceipt', async () => { - const txHash = '0x09dfb947dbd17e27bcc117773b6e133829f7cef9646199a93ef019c4f7c0fec6' + const txHash = '0x7262f7dbe6c30599edded2137fbbe93c271b37f5c54dd27f713f0cf510e3b4dd' const receipt = await foreignWeb3.eth.getTransactionReceipt(txHash) const selector = homeWeb3.utils.soliditySha3('eth_getTransactionReceipt(bytes32)') diff --git a/oracle/config/affirmation-request-watcher.config.js b/oracle/config/affirmation-request-watcher.config.js index 1a0da400..b63e113e 100644 --- a/oracle/config/affirmation-request-watcher.config.js +++ b/oracle/config/affirmation-request-watcher.config.js @@ -6,6 +6,7 @@ module.exports = { ...baseConfig, main: baseConfig.foreign, event: 'UserRequestForAffirmation', + sender: 'home', queue: 'home-prioritized', name: `watcher-${id}`, id diff --git a/oracle/config/collected-signatures-watcher.config.js b/oracle/config/collected-signatures-watcher.config.js index 1747bef3..7e299508 100644 --- a/oracle/config/collected-signatures-watcher.config.js +++ b/oracle/config/collected-signatures-watcher.config.js @@ -6,6 +6,7 @@ module.exports = { ...baseConfig, main: baseConfig.home, event: 'CollectedSignatures', + sender: 'foreign', queue: 'foreign-prioritized', name: `watcher-${id}`, id diff --git a/oracle/config/information-request-watcher.config.js b/oracle/config/information-request-watcher.config.js index 0431603f..6aa5a753 100644 --- a/oracle/config/information-request-watcher.config.js +++ b/oracle/config/information-request-watcher.config.js @@ -8,6 +8,7 @@ module.exports = { web3ForeignArchive: web3ForeignArchive || baseConfig.foreign.web3, main: baseConfig.home, event: 'UserRequestForInformation', + sender: 'home', queue: 'home-prioritized', name: `watcher-${id}`, id diff --git a/oracle/config/signature-request-watcher.config.js b/oracle/config/signature-request-watcher.config.js index 58bc832f..e7a54250 100644 --- a/oracle/config/signature-request-watcher.config.js +++ b/oracle/config/signature-request-watcher.config.js @@ -6,6 +6,7 @@ module.exports = { ...baseConfig, main: baseConfig.home, event: 'UserRequestForSignature', + sender: 'home', queue: 'home-prioritized', name: `watcher-${id}`, id diff --git a/oracle/config/transfer-watcher.config.js b/oracle/config/transfer-watcher.config.js index 94891c21..d25a63e2 100644 --- a/oracle/config/transfer-watcher.config.js +++ b/oracle/config/transfer-watcher.config.js @@ -30,6 +30,7 @@ module.exports = { }, event: 'Transfer', eventFilter: { to: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS }, + sender: 'home', queue: 'home-prioritized', name: `watcher-${id}`, id diff --git a/oracle/package.json b/oracle/package.json index 7f8eb359..8b4236e9 100644 --- a/oracle/package.json +++ b/oracle/package.json @@ -13,6 +13,10 @@ "sender:home": "./scripts/start-worker.sh sender home-sender", "sender:foreign": "./scripts/start-worker.sh sender foreign-sender", "confirm:transfer": "./scripts/start-worker.sh confirmRelay transfer-watcher", + "confirm:affirmation-request": "./scripts/start-worker.sh confirmRelay affirmation-request-watcher", + "confirm:signature-request": "./scripts/start-worker.sh confirmRelay signature-request-watcher", + "confirm:collected-signatures": "./scripts/start-worker.sh confirmRelay collected-signatures-watcher", + "confirm:information-request": "./scripts/start-worker.sh confirmRelay information-request-watcher", "manager:shutdown": "./scripts/start-worker.sh shutdownManager shutdown-manager", "dev": "concurrently -n 'watcher:signature-request,watcher:collected-signatures,watcher:affirmation-request,watcher:transfer, sender:home,sender:foreign' -c 'red,green,yellow,blue,magenta,cyan' 'yarn watcher:signature-request' 'yarn watcher:collected-signatures' 'yarn watcher:affirmation-request' 'yarn watcher:transfer' 'yarn sender:home' 'yarn sender:foreign'", "test": "NODE_ENV=test mocha", diff --git a/oracle/scripts/start-worker.sh b/oracle/scripts/start-worker.sh index c289dabc..6e21fbfc 100755 --- a/oracle/scripts/start-worker.sh +++ b/oracle/scripts/start-worker.sh @@ -8,12 +8,12 @@ LOGS_DIR="logs/" WORKER="${WORKERS_DIR}${1}.js" CONFIG="${2}.config.js" LOG="${LOGS_DIR}${2}.txt" -TX_HASH="${3}" +TX_HASH=${@:3} CHECKS=$(node scripts/initialChecks.js) if [ "${NODE_ENV}" = "production" ]; then - exec node "${WORKER}" "${CONFIG}" "$CHECKS" "$TX_HASH" + exec node "${WORKER}" "${CONFIG}" "$CHECKS" $TX_HASH else - node "${WORKER}" "${CONFIG}" "$CHECKS" "$TX_HASH" | tee -a "${LOG}" | pino-pretty + node "${WORKER}" "${CONFIG}" "$CHECKS" $TX_HASH | tee -a "${LOG}" | pino-pretty fi diff --git a/oracle/src/confirmRelay.js b/oracle/src/confirmRelay.js index 7bf5ba01..570ab412 100644 --- a/oracle/src/confirmRelay.js +++ b/oracle/src/confirmRelay.js @@ -1,5 +1,6 @@ require('../env') const path = require('path') +const fs = require('fs') const { isAttached, connectWatcherToQueue, connection } = require('./services/amqpClient') const logger = require('./services/logger') const GasPrice = require('./services/gasPrice') @@ -16,7 +17,22 @@ if (process.argv.length < 5) { } const config = require(path.join('../config/', process.argv[2])) -const txHash = process.argv[4] +const { web3, eventContract, chain } = config.main + +const isTxHash = txHash => txHash.length === 66 && web3.utils.isHexStrict(txHash) +function readTxHashes(filePath) { + return fs + .readFileSync(filePath) + .toString() + .split('\n') + .map(v => v.trim()) + .filter(isTxHash) +} + +const txHashesArgs = process.argv.slice(4) +const rawTxHashes = txHashesArgs.filter(isTxHash) +const txHashesFiles = txHashesArgs.filter(path => fs.existsSync(path)).flatMap(readTxHashes) +const txHashes = [...rawTxHashes, ...txHashesFiles] const processSignatureRequests = require('./events/processSignatureRequests')(config) const processCollectedSignatures = require('./events/processCollectedSignatures')(config) @@ -27,15 +43,13 @@ const processAMBCollectedSignatures = require('./events/processAMBCollectedSigna const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config) const processAMBInformationRequests = require('./events/processAMBInformationRequests')(config) -const { web3, eventContract } = config.main - let attached async function initialize() { try { const checkHttps = checkHTTPS(ORACLE_ALLOW_HTTP_FOR_RPC, logger) - web3.currentProvider.subProvider.urls.forEach(checkHttps(config.chain)) + web3.currentProvider.subProvider.urls.forEach(checkHttps(chain)) attached = await isAttached() if (attached) { @@ -59,12 +73,12 @@ async function runMain({ sendToQueue }) { const sendJob = attached ? sendToQueue : sendJobTx if (!attached || connection.isConnected()) { if (config.maxProcessingTime) { - await watchdog(() => main({ sendJob, txHash }), config.maxProcessingTime, () => { + await watchdog(() => main({ sendJob, txHashes }), config.maxProcessingTime, () => { logger.fatal('Max processing time reached') process.exit(EXIT_CODES.MAX_TIME_REACHED) }) } else { - await main({ sendJob, txHash }) + await main({ sendJob, txHashes }) } } else { setTimeout(() => { @@ -99,27 +113,31 @@ function processEvents(events) { } } -async function main({ sendJob, txHash }) { - try { - const events = await getEventsFromTx({ - web3, - contract: eventContract, - event: config.event, - txHash, - filter: config.eventFilter - }) - logger.info(`Found ${events.length} ${config.event} events`) +async function main({ sendJob, txHashes }) { + logger.info(`Processing ${txHashes.length} input transactions`) + for (const txHash of txHashes) { + try { + logger.info({ txHash }, `Processing transaction`) + const events = await getEventsFromTx({ + web3, + contract: eventContract, + event: config.event, + txHash, + filter: config.eventFilter + }) + logger.info({ txHash }, `Found ${events.length} ${config.event} events`) - if (events.length) { - const job = await processEvents(events) - logger.info('Transactions to send:', job.length) + if (events.length) { + const job = await processEvents(events) + logger.info({ txHash }, 'Transactions to send:', job.length) - if (job.length) { - await sendJob(job) + if (job.length) { + await sendJob(job) + } } + } catch (e) { + logger.error(e) } - } catch (e) { - logger.error(e) } await connection.close() @@ -128,7 +146,11 @@ async function main({ sendJob, txHash }) { } async function sendJobTx(jobs) { - const gasPrice = await GasPrice.start(config.chain, true) + await GasPrice.start(chain, true) + const gasPrice = GasPrice.getPrice().toString(10) + + const { web3 } = config.sender === 'foreign' ? config.foreign : config.home + const chainId = await getChainId(web3) let nonce = await getNonce(web3, ORACLE_VALIDATOR_ADDRESS) @@ -145,7 +167,7 @@ async function sendJobTx(jobs) { const txHash = await sendTx({ data: job.data, nonce, - gasPrice: gasPrice.toString(10), + gasPrice, amount: '0', gasLimit, privateKey: ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, diff --git a/oracle/src/sender.js b/oracle/src/sender.js index 7bb282c5..7c4fb534 100644 --- a/oracle/src/sender.js +++ b/oracle/src/sender.js @@ -40,7 +40,7 @@ async function initialize() { try { const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger) - web3.currentProvider.subProvider.urls.forEach(checkHttps(config.chain)) + web3.currentProvider.subProvider.urls.forEach(checkHttps(config.id)) GasPrice.start(config.id) diff --git a/oracle/src/tx/web3.js b/oracle/src/tx/web3.js index 5ad65ef8..33f98d4b 100644 --- a/oracle/src/tx/web3.js +++ b/oracle/src/tx/web3.js @@ -102,6 +102,7 @@ async function getEventsFromTx({ web3, contract, event, txHash, filter }) { const eventAbi = contract.options.jsonInterface.find(abi => abi.name === event) const decodeAbi = contract._decodeEventABI.bind(eventAbi) const pastEvents = logs + .filter(event => event.address.toLowerCase() === contractAddress.toLowerCase()) .filter(event => event.topics[0] === eventAbi.signature) .map(decodeAbi) .filter(event =>