From dc377aeb9bbaa3f1ad1734f93fbf5983287da5fa Mon Sep 17 00:00:00 2001 From: Kirill Fedoseev Date: Mon, 28 Sep 2020 14:54:03 +0300 Subject: [PATCH 1/7] Possibility to allow/block specific addresses in erc-to-native mode (#442) --- CONFIGURATION.md | 3 ++ alm-e2e/package.json | 2 +- e2e-commons/access-lists/allowance_list.txt | 0 e2e-commons/access-lists/block_list.txt | 1 + .../components-envs/oracle-erc20-native.env | 1 + e2e-commons/constants.json | 4 ++ e2e-commons/docker-compose.yml | 3 ++ monitor-e2e/package.json | 2 +- monitor/package.json | 2 +- oracle-e2e/package.json | 2 +- oracle-e2e/test/ercToNative.js | 45 +++++++++++++++- oracle/.env.example | 4 ++ oracle/docker-compose-erc-native.yml | 3 ++ oracle/package.json | 2 +- .../processCollectedSignatures/index.js | 52 ++++++++++++++++++- oracle/src/utils/utils.js | 25 ++++++++- parity/chain.json | 3 +- ui-e2e/package.json | 2 +- 18 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 e2e-commons/access-lists/allowance_list.txt create mode 100644 e2e-commons/access-lists/block_list.txt diff --git a/CONFIGURATION.md b/CONFIGURATION.md index f13d24b8..29469832 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -37,6 +37,9 @@ ORACLE_MAX_PROCESSING_TIME | The workers processes will be killed if this amount ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY | The private key of the bridge validator used to sign confirmations before sending transactions to the bridge contracts. The validator account is calculated automatically from the private key. Every bridge instance (set of watchers and senders) must have its own unique private key. The specified private key is used to sign transactions on both sides of the bridge. | hexidecimal without "0x" ORACLE_VALIDATOR_ADDRESS | The public address of the bridge validator | hexidecimal with "0x" ORACLE_TX_REDUNDANCY | If set to `true`, instructs oracle to send `eth_sendRawTransaction` requests through all available RPC urls defined in `COMMON_HOME_RPC_URL` and `COMMON_FOREIGN_RPC_URL` variables instead of using first available one +ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST | Filename with a list of addresses, separated by newlines. If set, determines the privileged set of accounts whose requests will be automatically processed by the CollectedSignatures watcher. | string +ORACLE_HOME_TO_FOREIGN_BLOCK_LIST | Filename with a list of addresses, separated by newlines. If set, determines the blocked set of accounts whose requests will not be automatically processed by the CollectedSignatures watcher. Has a lower priority than the `ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST` | string +ORACLE_HOME_TO_FOREIGN_CHECK_SENDER | If set to `true`, instructs the oracle to do an extra check for transaction origin in the block/allowance list. `false` by default. | `true` / `false` ## UI configuration diff --git a/alm-e2e/package.json b/alm-e2e/package.json index 31bfb03e..f7545a14 100644 --- a/alm-e2e/package.json +++ b/alm-e2e/package.json @@ -19,6 +19,6 @@ "eslint-plugin-jest": "^23.18.0" }, "engines": { - "node": ">= 8.9" + "node": ">= 10.18" } } diff --git a/e2e-commons/access-lists/allowance_list.txt b/e2e-commons/access-lists/allowance_list.txt new file mode 100644 index 00000000..e69de29b diff --git a/e2e-commons/access-lists/block_list.txt b/e2e-commons/access-lists/block_list.txt new file mode 100644 index 00000000..f130606c --- /dev/null +++ b/e2e-commons/access-lists/block_list.txt @@ -0,0 +1 @@ +0xc9e38bfdB9c635F0796ad83CC8705dc379F41c04 \ No newline at end of file diff --git a/e2e-commons/components-envs/oracle-erc20-native.env b/e2e-commons/components-envs/oracle-erc20-native.env index 13f773f2..7c40b987 100644 --- a/e2e-commons/components-envs/oracle-erc20-native.env +++ b/e2e-commons/components-envs/oracle-erc20-native.env @@ -23,3 +23,4 @@ ORACLE_FOREIGN_RPC_POLLING_INTERVAL=500 ORACLE_ALLOW_HTTP_FOR_RPC=yes ORACLE_HOME_START_BLOCK=1 ORACLE_FOREIGN_START_BLOCK=1 +ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=/mono/oracle/access-lists/block_list.txt diff --git a/e2e-commons/constants.json b/e2e-commons/constants.json index 904e1ba5..9aa0609b 100644 --- a/e2e-commons/constants.json +++ b/e2e-commons/constants.json @@ -15,6 +15,10 @@ "address": "0x3CC5baAB679eC0732C175760079Bf48F564ad26B", "privateKey": "0xedb53ee050631b7914d5f1a66c2f0d2df3ec85a9ed2a9616b16a7b1b7a10b8d1" }, + "blockedUser": { + "address": "0xc9e38bfdB9c635F0796ad83CC8705dc379F41c04", + "privateKey": "0x65df4ea787916f6ed9660f0b0fe36858a65735ad0dcd34527497f4ce32e53883" + }, "validator": { "address": "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b", "privateKey": "0x8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9" diff --git a/e2e-commons/docker-compose.yml b/e2e-commons/docker-compose.yml index 84939236..4fbd84c9 100644 --- a/e2e-commons/docker-compose.yml +++ b/e2e-commons/docker-compose.yml @@ -50,6 +50,9 @@ services: environment: - NODE_ENV=production command: "true" + volumes: + - '../e2e-commons/access-lists/block_list.txt:/mono/oracle/access-lists/block_list.txt' + - '../e2e-commons/access-lists/allowance_list.txt:/mono/oracle/access-lists/allowance_list.txt' networks: - ultimate oracle-amb: diff --git a/monitor-e2e/package.json b/monitor-e2e/package.json index 4dbb50e6..12a5b306 100644 --- a/monitor-e2e/package.json +++ b/monitor-e2e/package.json @@ -14,7 +14,7 @@ "axios": "0.19.0" }, "engines": { - "node": ">= 8.9" + "node": ">= 10.18" }, "devDependencies": {} } diff --git a/monitor/package.json b/monitor/package.json index 978df3f1..3b9c53ee 100644 --- a/monitor/package.json +++ b/monitor/package.json @@ -21,7 +21,7 @@ "web3": "1.0.0-beta.34" }, "engines": { - "node": ">=8.9" + "node": ">= 10.18" }, "devDependencies": { "chai": "^4.2.0" diff --git a/oracle-e2e/package.json b/oracle-e2e/package.json index 5cecdc4e..8ae5bc86 100644 --- a/oracle-e2e/package.json +++ b/oracle-e2e/package.json @@ -22,7 +22,7 @@ "websocket": "^1.0.28" }, "engines": { - "node": ">= 8.9" + "node": ">= 10.18" }, "devDependencies": {} } diff --git a/oracle-e2e/test/ercToNative.js b/oracle-e2e/test/ercToNative.js index 33b9092f..31867b37 100644 --- a/oracle-e2e/test/ercToNative.js +++ b/oracle-e2e/test/ercToNative.js @@ -4,13 +4,14 @@ const promiseRetry = require('promise-retry') const { user, secondUser, + blockedUser, validator, ercToNativeBridge, homeRPC, foreignRPC } = require('../../e2e-commons/constants.json') const { ERC677_BRIDGE_TOKEN_ABI, FOREIGN_ERC_TO_NATIVE_ABI, HOME_ERC_TO_NATIVE_ABI } = require('../../commons') -const { uniformRetry } = require('../../e2e-commons/utils') +const { uniformRetry, sleep } = require('../../e2e-commons/utils') const { setRequiredSignatures } = require('./utils') const homeWeb3 = new Web3(new Web3.providers.HttpProvider(homeRPC.URL)) @@ -22,6 +23,7 @@ const COMMON_FOREIGN_BRIDGE_ADDRESS = ercToNativeBridge.foreign const { toBN } = foreignWeb3.utils homeWeb3.eth.accounts.wallet.add(user.privateKey) +homeWeb3.eth.accounts.wallet.add(blockedUser.privateKey) homeWeb3.eth.accounts.wallet.add(validator.privateKey) foreignWeb3.eth.accounts.wallet.add(user.privateKey) foreignWeb3.eth.accounts.wallet.add(validator.privateKey) @@ -142,6 +144,47 @@ describe('erc to native', () => { } }) }) + it('should not process transaction from blocked users', async () => { + const originalBalance1 = await erc20Token.methods.balanceOf(user.address).call() + const originalBalance2 = await erc20Token.methods.balanceOf(blockedUser.address).call() + + // check that account has tokens in home chain + const balance1 = await homeWeb3.eth.getBalance(user.address) + const balance2 = await homeWeb3.eth.getBalance(blockedUser.address) + assert(!toBN(balance1).isZero(), 'Account should have tokens') + assert(!toBN(balance2).isZero(), 'Account should have tokens') + + // send transaction to home bridge + await homeWeb3.eth.sendTransaction({ + from: user.address, + to: COMMON_HOME_BRIDGE_ADDRESS, + gasPrice: '1', + gas: '1000000', + value: homeWeb3.utils.toWei('0.01') + }) + + // send transaction to home bridge + await homeWeb3.eth.sendTransaction({ + from: blockedUser.address, + to: COMMON_HOME_BRIDGE_ADDRESS, + gasPrice: '1', + gas: '1000000', + value: homeWeb3.utils.toWei('0.01') + }) + + // check that balance increases + await uniformRetry(async retry => { + const balance = await erc20Token.methods.balanceOf(user.address).call() + if (toBN(balance).lte(toBN(originalBalance1))) { + retry() + } + }) + + await sleep(3000) + + const balance = await erc20Token.methods.balanceOf(blockedUser.address).call() + assert(toBN(balance).eq(toBN(originalBalance2)), 'Bridge should not process collected signatures from blocked user') + }) it('should not invest dai when chai token is disabled', async () => { const bridgeDaiTokenBalance = await erc20Token.methods.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS).call() diff --git a/oracle/.env.example b/oracle/.env.example index 8376f0f7..0d5b45f2 100644 --- a/oracle/.env.example +++ b/oracle/.env.example @@ -30,6 +30,10 @@ ORACLE_FOREIGN_START_BLOCK= ORACLE_LOG_LEVEL=debug ORACLE_MAX_PROCESSING_TIME=20000 +ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST=access-lists/allowance_list.txt +ORACLE_HOME_TO_FOREIGN_BLOCK_LIST=access-lists/block_list.txt +ORACLE_HOME_TO_FOREIGN_CHECK_SENDER=false + #Uncomment these lines only if you are going to send transaction by testing scripts #USER_ADDRESS=0x59c4474184579b9c31b5e51445b6eef91cebf370 #USER_ADDRESS_PRIVATE_KEY= diff --git a/oracle/docker-compose-erc-native.yml b/oracle/docker-compose-erc-native.yml index cc642767..ed1a5d59 100644 --- a/oracle/docker-compose-erc-native.yml +++ b/oracle/docker-compose-erc-native.yml @@ -25,6 +25,9 @@ services: extends: file: docker-compose.yml service: bridge_collected + volumes: + - '~/bridge_data/access-lists/block_list.txt:/mono/oracle/access-lists/block_list.txt' + - '~/bridge_data/access-lists/allowance_list.txt:/mono/oracle/access-lists/allowance_list.txt' networks: - net_db_bridge_request - net_rabbit_bridge_request diff --git a/oracle/package.json b/oracle/package.json index 0eb384ee..1329b44e 100644 --- a/oracle/package.json +++ b/oracle/package.json @@ -48,6 +48,6 @@ "sinon": "^6.1.0" }, "engines": { - "node": ">= 8.9" + "node": ">= 10.18" } } diff --git a/oracle/src/events/processCollectedSignatures/index.js b/oracle/src/events/processCollectedSignatures/index.js index 04f6ed80..448168b6 100644 --- a/oracle/src/events/processCollectedSignatures/index.js +++ b/oracle/src/events/processCollectedSignatures/index.js @@ -4,11 +4,18 @@ 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, packSignatures } = require('../../utils/message') +const { signatureToVRS, packSignatures, parseMessage } = require('../../utils/message') +const { readAccessListFile } = require('../../utils/utils') const estimateGas = require('./estimateGas') const { AlreadyProcessedError, IncompatibleContractError, InvalidValidatorError } = require('../../utils/errors') const { MAX_CONCURRENT_EVENTS } = require('../../utils/constants') +const { + ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST, + ORACLE_HOME_TO_FOREIGN_BLOCK_LIST, + ORACLE_HOME_TO_FOREIGN_CHECK_SENDER +} = process.env + const limit = promiseLimit(MAX_CONCURRENT_EVENTS) let validatorContract = null @@ -46,6 +53,49 @@ function processCollectedSignaturesBuilder(config) { logger.info(`Processing CollectedSignatures ${colSignature.transactionHash}`) const message = await homeBridge.methods.message(messageHash).call() + if (ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST || ORACLE_HOME_TO_FOREIGN_BLOCK_LIST) { + const parsedMessage = parseMessage(message) + const recipient = parsedMessage.recipient.toLowerCase() + const originalTxHash = parsedMessage.txHash + + if (ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST) { + const allowanceList = await readAccessListFile(ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST, logger) + if (allowanceList.indexOf(recipient) === -1) { + if (ORACLE_HOME_TO_FOREIGN_CHECK_SENDER === 'true') { + logger.debug({ txHash: originalTxHash }, 'Requested sender of an original withdrawal transaction') + const sender = (await web3Home.eth.getTransaction(originalTxHash)).from.toLowerCase() + if (allowanceList.indexOf(sender) === -1) { + logger.info( + { sender, recipient }, + 'Validator skips a transaction. Neither sender nor recipient addresses are in the allowance list.' + ) + return + } + } else { + logger.info( + { recipient }, + 'Validator skips a transaction. Recipient address is not in the allowance list.' + ) + return + } + } + } else if (ORACLE_HOME_TO_FOREIGN_BLOCK_LIST) { + const blockList = await readAccessListFile(ORACLE_HOME_TO_FOREIGN_BLOCK_LIST, logger) + if (blockList.indexOf(recipient) > -1) { + logger.info({ recipient }, 'Validator skips a transaction. Recipient address is in the block list.') + return + } + if (ORACLE_HOME_TO_FOREIGN_CHECK_SENDER === 'true') { + logger.debug({ txHash: originalTxHash }, 'Requested sender of an original withdrawal transaction') + const sender = (await web3Home.eth.getTransaction(originalTxHash)).from.toLowerCase() + if (blockList.indexOf(sender) > -1) { + logger.info({ sender }, 'Validator skips a transaction. Sender address is in the block list.') + return + } + } + } + } + logger.debug({ NumberOfCollectedSignatures }, 'Number of signatures to get') const requiredSignatures = [] diff --git a/oracle/src/utils/utils.js b/oracle/src/utils/utils.js index 8de376ff..2db4d0f3 100644 --- a/oracle/src/utils/utils.js +++ b/oracle/src/utils/utils.js @@ -1,3 +1,4 @@ +const fs = require('fs') const BigNumber = require('bignumber.js') const promiseRetry = require('promise-retry') const Web3 = require('web3') @@ -105,6 +106,27 @@ function nonceError(e) { const invert = p => new Promise((res, rej) => p.then(rej, res)) const promiseAny = ps => invert(Promise.all(ps.map(invert))) +const readAccessLists = {} +async function readAccessListFile(fileName, logger) { + if (!readAccessLists[fileName]) { + logger.debug({ fileName }, 'Access list file read requested') + try { + const data = await fs.promises.readFile(fileName) + readAccessLists[fileName] = data + .toString() + .split('\n') + .map(addr => addr.trim().toLowerCase()) + .filter(addr => addr.length === 42) + logger.info({ fileName }, `Access list was read successfully, ${data.length} addresses found`) + logger.debug({ addresses: readAccessLists[fileName] }, `Read addresses from the file`) + } catch (e) { + readAccessLists[fileName] = [] + logger.error({ fileName, error: e }, `Failed to read access list from the file`) + } + } + return readAccessLists[fileName] +} + module.exports = { syncForEach, checkHTTPS, @@ -115,5 +137,6 @@ module.exports = { privateKeyToAddress, nonceError, getRetrySequence, - promiseAny + promiseAny, + readAccessListFile } diff --git a/parity/chain.json b/parity/chain.json index c135d6a8..7653c93d 100644 --- a/parity/chain.json +++ b/parity/chain.json @@ -51,6 +51,7 @@ "Dcef88209a20D52165230104B245803C3269454d": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "bb140FbA6242a1c3887A7823F7750a73101383e3": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "7FC1442AB55Da569940Eb750AaD2BAA63DA4010E": { "balance": "500000000000000000000" }, - "B4579fd5AfEaB60B03Db3F408AAdD315035943f7": { "balance": "500000000000000000000" } + "B4579fd5AfEaB60B03Db3F408AAdD315035943f7": { "balance": "500000000000000000000" }, + "c9e38bfdB9c635F0796ad83CC8705dc379F41c04": { "balance": "500000000000000000000" } } } diff --git a/ui-e2e/package.json b/ui-e2e/package.json index d065273b..279cc93e 100644 --- a/ui-e2e/package.json +++ b/ui-e2e/package.json @@ -11,6 +11,6 @@ "lint": "eslint . --ignore-path ../.eslintignore" }, "engines": { - "node": ">= 8.9" + "node": ">= 10.18" } } From 4e04f2ae1f81959f4bb14826b6108adfab1b8bfa Mon Sep 17 00:00:00 2001 From: Kirill Fedoseev Date: Wed, 30 Sep 2020 19:30:51 +0300 Subject: [PATCH 2/7] Update the condition for checking if a tx was stuck (#444) --- oracle/src/sender.js | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/oracle/src/sender.js b/oracle/src/sender.js index c6fbde30..4a84aeb7 100644 --- a/oracle/src/sender.js +++ b/oracle/src/sender.js @@ -123,38 +123,32 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT } try { - let txNonce if (isResend) { const tx = await web3Instance.eth.getTransaction(job.txHash) - if (tx === null) { - logger.info(`Transaction ${job.txHash} was not found, dropping it`) - return - } - if (tx.blockNumber !== null) { - logger.info(`Transaction ${job.txHash} was successfully mined`) + if (tx && tx.blockNumber !== null) { + logger.debug(`Transaction ${job.txHash} was successfully mined`) return } logger.info( - `Previously sent transaction is stuck, updating gasPrice: ${tx.gasPrice} -> ${gasPrice.toString(10)}` + `Previously sent transaction is stuck, updating gasPrice: ${job.gasPrice} -> ${gasPrice.toString(10)}` ) - if (toBN(tx.gasPrice).gte(toBN(gasPrice))) { + if (toBN(job.gasPrice).gte(toBN(gasPrice))) { logger.info("Gas price returned from the oracle didn't increase, will reinspect this transaction later") sentTx.push(job) return } - - txNonce = tx.nonce } else { - txNonce = nonce++ + job.nonce = nonce++ } - logger.info(`Sending transaction with nonce ${txNonce}`) - const txHash = await sendTx({ + logger.info(`Sending transaction with nonce ${job.nonce}`) + job.gasPrice = gasPrice.toString(10) + job.txHash = await sendTx({ chain: config.id, data: job.data, - nonce: txNonce, - gasPrice: gasPrice.toString(10), + nonce: job.nonce, + gasPrice: job.gasPrice, amount: '0', gasLimit, privateKey: ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, @@ -162,14 +156,11 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT chainId, web3: web3Instance }) - sentTx.push({ - ...job, - txHash - }) + sentTx.push(job) logger.info( - { eventTransactionHash: job.transactionReference, generatedTransactionHash: txHash }, - `Tx generated ${txHash} for event Tx ${job.transactionReference}` + { eventTransactionHash: job.transactionReference, generatedTransactionHash: job.txHash }, + `Tx generated ${job.txHash} for event Tx ${job.transactionReference}` ) } catch (e) { logger.error( From 7a0ed3f6996583015b5e5b1ec84470734bffbb4c Mon Sep 17 00:00:00 2001 From: Alexander Kolotov Date: Thu, 1 Oct 2020 10:52:22 +0300 Subject: [PATCH 3/7] Small update of the execution waiting status description in ALM (#456) --- alm/src/config/descriptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alm/src/config/descriptions.ts b/alm/src/config/descriptions.ts index dd2ed174..7d6682b0 100644 --- a/alm/src/config/descriptions.ts +++ b/alm/src/config/descriptions.ts @@ -59,7 +59,7 @@ export const CONFIRMATIONS_STATUS_DESCRIPTION_HOME: { [key: string]: string } = EXECUTION_PENDING: 'The specified transaction was included in a block\nand the validators collected signatures. The\nvalidator’s transaction with collected signatures was\nsent but is not yet added to a block.', EXECUTION_WAITING: - 'The specified transaction was included in a block\nand the validators collected signatures. Either\n1. One of the validators is waiting for chain finalization.\n2. A validator skipped its duty to relay signatures.\nCheck status again after a few blocks. If the issue still persists contact to the validators by messaging on %linkhttps://forum.poa.network/c/support', + 'The specified transaction was included in a block\nand the validators collected signatures. Either\n1. One of the validators is waiting for chain finalization.\n2. A validator skipped its duty to relay signatures.\n3. The execution transaction is still pending (e.g. due to the gas price spike).\nCheck status again after a few blocks. If the issue still persists contact to the validators by messaging on %linkhttps://forum.poa.network/c/support', FAILED: 'The specified transaction was included in a block,\nbut transactions with signatures sent by a majority of\nvalidators failed. The cross-chain relay request will\nnot be processed. Contact to the validators by\nmessaging on %linkhttps://forum.poa.network/c/support', PENDING: From 125b66b86d75168fbb15e018f67b58d3814104ab Mon Sep 17 00:00:00 2001 From: Alexander Kolotov Date: Thu, 1 Oct 2020 10:53:11 +0300 Subject: [PATCH 4/7] Update requirements for higher bound of gas price (#458) --- oracle/src/utils/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oracle/src/utils/constants.js b/oracle/src/utils/constants.js index e1fcb20b..f3b5b177 100644 --- a/oracle/src/utils/constants.js +++ b/oracle/src/utils/constants.js @@ -21,7 +21,7 @@ module.exports = { }, GAS_PRICE_BOUNDARIES: { MIN: 1, - MAX: 250 + MAX: 1000 }, TRANSACTION_RESEND_TIMEOUT: 20 * 60 * 1000, SENDER_QUEUE_MAX_PRIORITY: 10, From 4cc87ef61a890f5469468e1f868789f8e75018fe Mon Sep 17 00:00:00 2001 From: Kirill Fedoseev Date: Fri, 2 Oct 2020 19:07:40 +0300 Subject: [PATCH 5/7] Use totalExecutedPerDay instead of totalSpentPerDay for calculating quota (#460) --- ui/src/stores/ForeignStore.js | 2 +- ui/src/stores/HomeStore.js | 6 +++++- ui/src/stores/utils/contract.js | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ui/src/stores/ForeignStore.js b/ui/src/stores/ForeignStore.js index 58e9b407..f97ed7ca 100644 --- a/ui/src/stores/ForeignStore.js +++ b/ui/src/stores/ForeignStore.js @@ -325,7 +325,7 @@ class ForeignStore { @action async getCurrentLimit() { try { - const result = await getCurrentLimit(this.foreignBridge, this.tokenDecimals) + const result = await getCurrentLimit(this.foreignBridge, this.homeStore.homeBridge, this.tokenDecimals) this.maxCurrentDeposit = result.maxCurrentDeposit this.dailyLimit = result.dailyLimit this.totalSpentPerDay = result.totalSpentPerDay diff --git a/ui/src/stores/HomeStore.js b/ui/src/stores/HomeStore.js index 99265046..1dbc9d01 100644 --- a/ui/src/stores/HomeStore.js +++ b/ui/src/stores/HomeStore.js @@ -429,7 +429,11 @@ class HomeStore { @action async getCurrentLimit() { try { - const result = await getCurrentLimit(this.homeBridge, this.tokenDecimals) + const result = await getCurrentLimit( + this.homeBridge, + this.rootStore.foreignStore.foreignBridge, + this.tokenDecimals + ) this.maxCurrentDeposit = result.maxCurrentDeposit this.dailyLimit = result.dailyLimit this.totalSpentPerDay = result.totalSpentPerDay diff --git a/ui/src/stores/utils/contract.js b/ui/src/stores/utils/contract.js index 8756b764..1bccc7d2 100644 --- a/ui/src/stores/utils/contract.js +++ b/ui/src/stores/utils/contract.js @@ -21,10 +21,10 @@ export const getMinPerTxLimit = async (contract, decimals) => { return fromDecimals(minPerTx, decimals) } -export const getCurrentLimit = async (contract, decimals) => { +export const getCurrentLimit = async (contract, otherContract, decimals) => { const currentDay = await contract.methods.getCurrentDay().call() const dailyLimit = await contract.methods.dailyLimit().call() - const totalSpentPerDay = await contract.methods.totalSpentPerDay(currentDay).call() + const totalSpentPerDay = await otherContract.methods.totalExecutedPerDay(currentDay).call() const maxCurrentDeposit = new BN(dailyLimit).minus(new BN(totalSpentPerDay)).toString(10) return { maxCurrentDeposit: fromDecimals(maxCurrentDeposit, decimals), From d17ea2ad2b65f4f19f16c31a332ad8953a6e9ade Mon Sep 17 00:00:00 2001 From: Alexander Kolotov Date: Fri, 2 Oct 2020 19:44:05 +0300 Subject: [PATCH 6/7] One point of handling all collected signatures requests (#457) --- CONFIGURATION.md | 3 ++- oracle/src/events/processAMBCollectedSignatures/index.js | 6 +++++- oracle/src/events/processCollectedSignatures/index.js | 7 +++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 29469832..da514fb2 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -22,7 +22,7 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR | A value that will multiply the gas price of th name | description | value --- | --- | --- -ORACLE_BRIDGE_MODE | The bridge mode. The bridge starts listening to a different set of events based on this parameter. | NATIVE_TO_ERC / ERC_TO_ERC / ERC_TO_NATIVE +ORACLE_BRIDGE_MODE | The bridge mode. The bridge starts listening to a different set of events based on this parameter. | NATIVE_TO_ERC / ERC_TO_ERC / ERC_TO_NATIVE / ARBITRARY_MESSAGE ORACLE_ALLOW_HTTP_FOR_RPC | **Only use in test environments - must be omitted in production environments.**. If this parameter is specified and set to `yes`, RPC URLs can be specified in form of HTTP links. A warning that the connection is insecure will be written to the logs. | `yes` / `no` ORACLE_HOME_RPC_POLLING_INTERVAL | The interval in milliseconds used to request the RPC node in the Home network for new blocks. The interval should match the average production time for a new block. | integer ORACLE_FOREIGN_RPC_POLLING_INTERVAL | The interval in milliseconds used to request the RPC node in the Foreign network for new blocks. The interval should match the average production time for a new block. | integer @@ -40,6 +40,7 @@ ORACLE_TX_REDUNDANCY | If set to `true`, instructs oracle to send `eth_sendRawTr ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST | Filename with a list of addresses, separated by newlines. If set, determines the privileged set of accounts whose requests will be automatically processed by the CollectedSignatures watcher. | string ORACLE_HOME_TO_FOREIGN_BLOCK_LIST | Filename with a list of addresses, separated by newlines. If set, determines the blocked set of accounts whose requests will not be automatically processed by the CollectedSignatures watcher. Has a lower priority than the `ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST` | string ORACLE_HOME_TO_FOREIGN_CHECK_SENDER | If set to `true`, instructs the oracle to do an extra check for transaction origin in the block/allowance list. `false` by default. | `true` / `false` +ORACLE_ALWAYS_RELAY_SIGNATURES | If set to `true`, the oracle will always relay signatures even if it was not the last who finilized the signatures collecting process. The default is `false`. | `true` / `false` ## UI configuration diff --git a/oracle/src/events/processAMBCollectedSignatures/index.js b/oracle/src/events/processAMBCollectedSignatures/index.js index 6985953f..05af5397 100644 --- a/oracle/src/events/processAMBCollectedSignatures/index.js +++ b/oracle/src/events/processAMBCollectedSignatures/index.js @@ -12,6 +12,8 @@ const { MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/const const limit = promiseLimit(MAX_CONCURRENT_EVENTS) +const { ORACLE_ALWAYS_RELAY_SIGNATURES } = process.env + let validatorContract = null function processCollectedSignaturesBuilder(config) { @@ -39,7 +41,9 @@ function processCollectedSignaturesBuilder(config) { eventTransactionHash: colSignature.transactionHash }) - if (authorityResponsibleForRelay !== web3Home.utils.toChecksumAddress(config.validatorAddress)) { + if (ORACLE_ALWAYS_RELAY_SIGNATURES && ORACLE_ALWAYS_RELAY_SIGNATURES === 'true') { + logger.debug('Validator handles all CollectedSignature requests') + } else if (authorityResponsibleForRelay !== web3Home.utils.toChecksumAddress(config.validatorAddress)) { logger.info(`Validator not responsible for relaying CollectedSignatures ${colSignature.transactionHash}`) return } diff --git a/oracle/src/events/processCollectedSignatures/index.js b/oracle/src/events/processCollectedSignatures/index.js index 448168b6..91e21ba4 100644 --- a/oracle/src/events/processCollectedSignatures/index.js +++ b/oracle/src/events/processCollectedSignatures/index.js @@ -13,7 +13,8 @@ const { MAX_CONCURRENT_EVENTS } = require('../../utils/constants') const { ORACLE_HOME_TO_FOREIGN_ALLOWANCE_LIST, ORACLE_HOME_TO_FOREIGN_BLOCK_LIST, - ORACLE_HOME_TO_FOREIGN_CHECK_SENDER + ORACLE_HOME_TO_FOREIGN_CHECK_SENDER, + ORACLE_ALWAYS_RELAY_SIGNATURES } = process.env const limit = promiseLimit(MAX_CONCURRENT_EVENTS) @@ -45,7 +46,9 @@ function processCollectedSignaturesBuilder(config) { eventTransactionHash: colSignature.transactionHash }) - if (authorityResponsibleForRelay !== web3Home.utils.toChecksumAddress(config.validatorAddress)) { + if (ORACLE_ALWAYS_RELAY_SIGNATURES && ORACLE_ALWAYS_RELAY_SIGNATURES === 'true') { + logger.debug('Validator handles all CollectedSignature requests') + } else if (authorityResponsibleForRelay !== web3Home.utils.toChecksumAddress(config.validatorAddress)) { logger.info(`Validator not responsible for relaying CollectedSignatures ${colSignature.transactionHash}`) return } From fbeb878cdbae5ddfb50696cff7c29ee5d89ae752 Mon Sep 17 00:00:00 2001 From: Kirill Fedoseev Date: Fri, 2 Oct 2020 19:46:07 +0300 Subject: [PATCH 7/7] Fix insufficient funds error handler (#459) --- oracle/src/confirmRelay.js | 2 +- oracle/src/sender.js | 35 +++++++++++++++++------------------ oracle/src/utils/utils.js | 7 ++++--- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/oracle/src/confirmRelay.js b/oracle/src/confirmRelay.js index d7b45043..15eeb70e 100644 --- a/oracle/src/confirmRelay.js +++ b/oracle/src/confirmRelay.js @@ -177,7 +177,7 @@ async function sendJobTx(jobs) { e.message ) - if (e.message.includes('Insufficient funds')) { + if (e.message.toLowerCase().includes('insufficient funds')) { const currentBalance = await web3Instance.eth.getBalance(ORACLE_VALIDATOR_ADDRESS) const minimumBalance = gasLimit.multipliedBy(gasPrice) logger.error( diff --git a/oracle/src/sender.js b/oracle/src/sender.js index 4a84aeb7..22585282 100644 --- a/oracle/src/sender.js +++ b/oracle/src/sender.js @@ -1,6 +1,5 @@ require('../env') const path = require('path') -const { toBN } = require('web3-utils') const { connectSenderToQueue } = require('./services/amqpClient') const { redis } = require('./services/redisClient') const GasPrice = require('./services/gasPrice') @@ -98,10 +97,10 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT } const txArray = JSON.parse(msg.content) - logger.info(`Msg received with ${txArray.length} Tx to send`) + logger.debug(`Msg received with ${txArray.length} Tx to send`) const gasPrice = GasPrice.getPrice() - let nonce = await readNonce() + let nonce let insufficientFunds = false let minimumBalance = null const failedTx = [] @@ -110,9 +109,11 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT const isResend = txArray.length > 0 && !!txArray[0].txHash if (isResend) { - logger.debug(`Checking status of ${txArray.length} transactions`) + logger.info(`Checking status of ${txArray.length} transactions`) + nonce = null } else { - logger.debug(`Sending ${txArray.length} transactions`) + logger.info(`Sending ${txArray.length} transactions`) + nonce = await readNonce() } await syncForEach(txArray, async job => { let gasLimit @@ -131,23 +132,20 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT return } - logger.info( - `Previously sent transaction is stuck, updating gasPrice: ${job.gasPrice} -> ${gasPrice.toString(10)}` - ) - if (toBN(job.gasPrice).gte(toBN(gasPrice))) { - logger.info("Gas price returned from the oracle didn't increase, will reinspect this transaction later") - sentTx.push(job) - return + if (nonce === null) { + nonce = await readNonce(true) } - } else { - job.nonce = nonce++ + + logger.info( + `Transaction ${job.txHash} was not mined, updating gasPrice: ${job.gasPrice} -> ${gasPrice.toString(10)}` + ) } - logger.info(`Sending transaction with nonce ${job.nonce}`) + logger.info(`Sending transaction with nonce ${nonce}`) job.gasPrice = gasPrice.toString(10) job.txHash = await sendTx({ chain: config.id, data: job.data, - nonce: job.nonce, + nonce, gasPrice: job.gasPrice, amount: '0', gasLimit, @@ -158,6 +156,7 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT }) sentTx.push(job) + nonce++ logger.info( { eventTransactionHash: job.transactionReference, generatedTransactionHash: job.txHash }, `Tx generated ${job.txHash} for event Tx ${job.transactionReference}` @@ -168,11 +167,11 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT `Tx Failed for event Tx ${job.transactionReference}.`, e.message ) - if (!e.message.includes('Transaction with the same hash was already imported')) { + if (!e.message.toLowerCase().includes('transaction with the same hash was already imported')) { failedTx.push(job) } - if (e.message.includes('Insufficient funds')) { + if (e.message.toLowerCase().includes('insufficient funds')) { insufficientFunds = true const currentBalance = await web3Instance.eth.getBalance(ORACLE_VALIDATOR_ADDRESS) minimumBalance = gasLimit.multipliedBy(gasPrice) diff --git a/oracle/src/utils/utils.js b/oracle/src/utils/utils.js index 2db4d0f3..7ce89b2a 100644 --- a/oracle/src/utils/utils.js +++ b/oracle/src/utils/utils.js @@ -94,10 +94,11 @@ function privateKeyToAddress(privateKey) { } function nonceError(e) { + const message = e.message.toLowerCase() return ( - e.message.includes('Transaction nonce is too low') || - e.message.includes('nonce too low') || - e.message.includes('transaction with same nonce in the queue') + message.includes('transaction nonce is too low') || + message.includes('nonce too low') || + message.includes('transaction with same nonce in the queue') ) }