Compare commits

..

3 Commits

Author SHA1 Message Date
Kirill Fedoseev
a973e23a9e Use UserRequestForInformation as starting block for InformationRetrieved search 2021-07-13 11:32:51 +03:00
Kirill Fedoseev
a1e258f424 Add extra validation for already processed information requests 2021-07-13 02:05:13 +03:00
Kirill Fedoseev
e976dac616 Update block,tx,receipt seriailizer methods to include more fields 2021-07-12 21:46:53 +03:00
13 changed files with 19 additions and 82 deletions

View File

@@ -19,7 +19,6 @@ COPY --from=contracts /mono/contracts/build ./contracts/build
COPY commons/package.json ./commons/ COPY commons/package.json ./commons/
COPY oracle-e2e/package.json ./oracle-e2e/ COPY oracle-e2e/package.json ./oracle-e2e/
COPY monitor-e2e/package.json ./monitor-e2e/ COPY monitor-e2e/package.json ./monitor-e2e/
COPY oracle/src/utils/constants.js ./oracle/src/utils/constants.js
COPY yarn.lock . COPY yarn.lock .
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production

View File

@@ -1,6 +1,5 @@
const Web3 = require('web3') const Web3 = require('web3')
const assert = require('assert') const assert = require('assert')
const { ASYNC_CALL_ERRORS } = require('../../oracle/src/utils/constants')
const { user, homeRPC, foreignRPC, amb, validator } = require('../../e2e-commons/constants.json') const { user, homeRPC, foreignRPC, amb, validator } = require('../../e2e-commons/constants.json')
const { uniformRetry } = require('../../e2e-commons/utils') const { uniformRetry } = require('../../e2e-commons/utils')
const { BOX_ABI, HOME_AMB_ABI, FOREIGN_AMB_ABI, ambInformationSignatures } = require('../../commons') const { BOX_ABI, HOME_AMB_ABI, FOREIGN_AMB_ABI, ambInformationSignatures } = require('../../commons')
@@ -304,7 +303,7 @@ describe('arbitrary message bridging', () => {
await makeAsyncCall(selector, data2) await makeAsyncCall(selector, data2)
assert(!(await homeBox.methods.status().call()), 'status is true') assert(!(await homeBox.methods.status().call()), 'status is true')
assert.strictEqual(await homeBox.methods.data().call(), ASYNC_CALL_ERRORS.REVERT, 'returned data is incorrect') assert.strictEqual(await homeBox.methods.data().call(), null, 'returned data is incorrect')
const data3 = homeWeb3.eth.abi.encodeParameters( const data3 = homeWeb3.eth.abi.encodeParameters(
['address', 'address', 'uint256', 'bytes'], ['address', 'address', 'uint256', 'bytes'],
@@ -314,7 +313,7 @@ describe('arbitrary message bridging', () => {
await makeAsyncCall(selector, data3) await makeAsyncCall(selector, data3)
assert(!(await homeBox.methods.status().call()), 'status is true') assert(!(await homeBox.methods.status().call()), 'status is true')
assert.strictEqual(await homeBox.methods.data().call(), ASYNC_CALL_ERRORS.REVERT, 'returned data is incorrect') assert.strictEqual(await homeBox.methods.data().call(), null, 'returned data is incorrect')
}) })
it('should make async eth_call for specific block', async () => { it('should make async eth_call for specific block', async () => {
@@ -355,11 +354,6 @@ describe('arbitrary message bridging', () => {
await makeAsyncCall(selector, data3) await makeAsyncCall(selector, data3)
assert(!(await homeBox.methods.status().call()), 'status is true') assert(!(await homeBox.methods.status().call()), 'status is true')
assert.strictEqual(
await homeBox.methods.data().call(),
ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE,
'returned data is incorrect'
)
}) })
it('should make async eth_blockNumber', async () => { it('should make async eth_blockNumber', async () => {

View File

@@ -1,7 +1,6 @@
const { toBN } = require('web3').utils const { toBN } = require('web3').utils
const { ASYNC_CALL_ERRORS, ASYNC_ETH_CALL_MAX_GAS_LIMIT } = require('../../../utils/constants') const { zipToObject } = require('../../../utils/utils')
const { zipToObject, isRevertError } = require('../../../utils/utils')
const argTypes = { const argTypes = {
to: 'address', to: 'address',
@@ -18,23 +17,14 @@ function makeCall(argNames) {
const { blockNumber, ...opts } = zipToObject(argNames, args) const { blockNumber, ...opts } = zipToObject(argNames, args)
if (blockNumber && toBN(blockNumber).gt(toBN(foreignBlock.number))) { if (blockNumber && toBN(blockNumber).gt(toBN(foreignBlock.number))) {
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE] return [false, '0x']
} }
// different clients might use different default gas limits, so it makes sense to limit it by some large number const [status, result] = await web3.eth
if (!opts.gas || toBN(opts.gas).gt(toBN(ASYNC_ETH_CALL_MAX_GAS_LIMIT))) {
opts.gas = ASYNC_ETH_CALL_MAX_GAS_LIMIT
}
return web3.eth
.call(opts, blockNumber || foreignBlock.number) .call(opts, blockNumber || foreignBlock.number)
.then(result => [true, web3.eth.abi.encodeParameter('bytes', result)]) .then(result => [true, result], err => [false, err.data])
.catch(e => {
if (isRevertError(e)) { return [status, web3.eth.abi.encodeParameter('bytes', result)]
return [false, ASYNC_CALL_ERRORS.REVERT]
}
throw e
})
} }
} }

View File

@@ -1,7 +1,5 @@
const { toBN } = require('web3').utils const { toBN } = require('web3').utils
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
async function call(web3, data, foreignBlock) { async function call(web3, data, foreignBlock) {
const address = web3.eth.abi.decodeParameter('address', data) const address = web3.eth.abi.decodeParameter('address', data)
@@ -14,7 +12,7 @@ async function callArchive(web3, data, foreignBlock) {
const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data) const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) { if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE] return [false, '0x']
} }
const balance = await web3.eth.getBalance(address, blockNumber) const balance = await web3.eth.getBalance(address, blockNumber)

View File

@@ -1,4 +1,3 @@
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
const { serializeBlock } = require('./serializers') const { serializeBlock } = require('./serializers')
async function call(web3, data, foreignBlock) { async function call(web3, data, foreignBlock) {
@@ -7,7 +6,7 @@ async function call(web3, data, foreignBlock) {
const block = await web3.eth.getBlock(blockHash) const block = await web3.eth.getBlock(blockHash)
if (block === null || block.number > foreignBlock.number) { if (block === null || block.number > foreignBlock.number) {
return [false, ASYNC_CALL_ERRORS.NOT_FOUND] return [false, '0x']
} }
return [true, serializeBlock(web3, block)] return [true, serializeBlock(web3, block)]

View File

@@ -1,13 +1,12 @@
const { toBN } = require('web3').utils const { toBN } = require('web3').utils
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
const { serializeBlock } = require('./serializers') const { serializeBlock } = require('./serializers')
async function call(web3, data, foreignBlock) { async function call(web3, data, foreignBlock) {
const blockNumber = web3.eth.abi.decodeParameter('uint256', data) const blockNumber = web3.eth.abi.decodeParameter('uint256', data)
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) { if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE] return [false, '0x']
} }
const block = await web3.eth.getBlock(blockNumber) const block = await web3.eth.getBlock(blockNumber)

View File

@@ -1,7 +1,5 @@
const { toBN } = require('web3').utils const { toBN } = require('web3').utils
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
async function call(web3, data, foreignBlock) { async function call(web3, data, foreignBlock) {
const { 0: address, 1: slot } = web3.eth.abi.decodeParameters(['address', 'bytes32'], data) const { 0: address, 1: slot } = web3.eth.abi.decodeParameters(['address', 'bytes32'], data)
@@ -14,7 +12,7 @@ async function callArchive(web3, data, foreignBlock) {
const { 0: address, 1: slot, 2: blockNumber } = web3.eth.abi.decodeParameters(['address', 'bytes32', 'uint256'], data) const { 0: address, 1: slot, 2: blockNumber } = web3.eth.abi.decodeParameters(['address', 'bytes32', 'uint256'], data)
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) { if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE] return [false, '0x']
} }
const value = await web3.eth.getStorageAt(address, slot, blockNumber) const value = await web3.eth.getStorageAt(address, slot, blockNumber)

View File

@@ -1,4 +1,3 @@
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
const { serializeTx } = require('./serializers') const { serializeTx } = require('./serializers')
async function call(web3, data, foreignBlock) { async function call(web3, data, foreignBlock) {
@@ -7,7 +6,7 @@ async function call(web3, data, foreignBlock) {
const tx = await web3.eth.getTransaction(hash) const tx = await web3.eth.getTransaction(hash)
if (tx === null || tx.blockNumber > foreignBlock.number) { if (tx === null || tx.blockNumber > foreignBlock.number) {
return [false, ASYNC_CALL_ERRORS.NOT_FOUND] return [false, '0x']
} }
return [true, serializeTx(web3, tx)] return [true, serializeTx(web3, tx)]

View File

@@ -1,7 +1,5 @@
const { toBN } = require('web3').utils const { toBN } = require('web3').utils
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
async function call(web3, data, foreignBlock) { async function call(web3, data, foreignBlock) {
const address = web3.eth.abi.decodeParameter('address', data) const address = web3.eth.abi.decodeParameter('address', data)
@@ -14,7 +12,7 @@ async function callArchive(web3, data, foreignBlock) {
const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data) const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) { if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE] return [false, '0x']
} }
const nonce = await web3.eth.getTransactionCount(address, blockNumber) const nonce = await web3.eth.getTransactionCount(address, blockNumber)

View File

@@ -1,4 +1,3 @@
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
const { serializeReceipt } = require('./serializers') const { serializeReceipt } = require('./serializers')
async function call(web3, data, foreignBlock) { async function call(web3, data, foreignBlock) {
@@ -7,7 +6,7 @@ async function call(web3, data, foreignBlock) {
const receipt = await web3.eth.getTransactionReceipt(hash) const receipt = await web3.eth.getTransactionReceipt(hash)
if (receipt === null || receipt.blockNumber > foreignBlock.number) { if (receipt === null || receipt.blockNumber > foreignBlock.number) {
return [false, ASYNC_CALL_ERRORS.NOT_FOUND] return [false, '0x']
} }
return [true, serializeReceipt(web3, receipt)] return [true, serializeReceipt(web3, receipt)]

View File

@@ -4,13 +4,7 @@ const { soliditySha3 } = require('web3').utils
const { HttpListProviderError } = require('../../services/HttpListProvider') const { HttpListProviderError } = require('../../services/HttpListProvider')
const rootLogger = require('../../services/logger') const rootLogger = require('../../services/logger')
const makeBlockFinder = require('../../services/blockFinder') const makeBlockFinder = require('../../services/blockFinder')
const { const { EXIT_CODES, MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/constants')
EXIT_CODES,
MAX_CONCURRENT_EVENTS,
EXTRA_GAS_ABSOLUTE,
ASYNC_CALL_ERRORS,
MAX_ASYNC_CALL_RESULT_LENGTH
} = require('../../utils/constants')
const estimateGas = require('./estimateGas') const estimateGas = require('./estimateGas')
const { getValidatorContract, getBlock, getBlockNumber, getRequiredBlockConfirmations } = require('../../tx/web3') const { getValidatorContract, getBlock, getBlockNumber, getRequiredBlockConfirmations } = require('../../tx/web3')
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors') const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
@@ -85,17 +79,12 @@ function processInformationRequestsBuilder(config) {
logger.info({ requestSelector, method: asyncCallMethod, data }, 'Processing async request') logger.info({ requestSelector, method: asyncCallMethod, data }, 'Processing async request')
const call = asyncCalls[asyncCallMethod] const call = asyncCalls[asyncCallMethod]
let [status, result] = await call(web3ForeignArchive, data, foreignClosestBlock).catch(e => { const [status, result] = await call(web3ForeignArchive, data, foreignClosestBlock).catch(e => {
if (e instanceof HttpListProviderError) { if (e instanceof HttpListProviderError) {
throw e throw e
} }
logger.error({ error: e.message }, 'Unknown error during async call execution') return [false, '0x']
throw e
}) })
if (result.length > 2 + MAX_ASYNC_CALL_RESULT_LENGTH * 2) {
status = false
result = ASYNC_CALL_ERRORS.RESULT_IS_TOO_LONG
}
logger.info({ requestSelector, method: asyncCallMethod, status, result }, 'Request result obtained') logger.info({ requestSelector, method: asyncCallMethod, status, result }, 'Request result obtained')
let gasEstimate let gasEstimate

View File

@@ -27,17 +27,5 @@ module.exports = {
FALLBACK_RPC_URL_SWITCH_TIMEOUT: 60 * 60 * 1000, FALLBACK_RPC_URL_SWITCH_TIMEOUT: 60 * 60 * 1000,
SENDER_QUEUE_MAX_PRIORITY: 10, SENDER_QUEUE_MAX_PRIORITY: 10,
SENDER_QUEUE_SEND_PRIORITY: 5, SENDER_QUEUE_SEND_PRIORITY: 5,
SENDER_QUEUE_CHECK_STATUS_PRIORITY: 1, SENDER_QUEUE_CHECK_STATUS_PRIORITY: 1
ASYNC_CALL_ERRORS: {
// requested transaction/block/receipt does not exist
NOT_FOUND: '0x0000000000000000000000000000000000000000000000000000000000000000',
// requested custom block does not exist yet or its timestamp is greater than the home block timestamp
BLOCK_IS_IN_THE_FUTURE: '0x0000000000000000000000000000000000000000000000000000000000000001',
// eth_call has reverted or finished with OOG error
REVERT: '0x0000000000000000000000000000000000000000000000000000000000000002',
// evaluated output length exceeds allowed length of 64 KB
RESULT_IS_TOO_LONG: '0x0000000000000000000000000000000000000000000000000000000000000003'
},
MAX_ASYNC_CALL_RESULT_LENGTH: 64 * 1024,
ASYNC_ETH_CALL_MAX_GAS_LIMIT: 100000000
} }

View File

@@ -123,18 +123,6 @@ function isNonceError(e) {
) )
} }
function isRevertError(e) {
const message = e.message.toLowerCase()
// OE and NE returns "VM execution error"/"Transaction execution error"
// Geth returns "out of gas"/"intrinsic gas too low"/"execution reverted"
return (
message.includes('execution error') ||
message.includes('intrinsic gas too low') ||
message.includes('out of gas') ||
message.includes('execution reverted')
)
}
// Promise.all rejects on the first rejected Promise or fulfills with the list of results // Promise.all rejects on the first rejected Promise or fulfills with the list of results
// inverted Promise.all fulfills with the first obtained result or rejects with the list of errors // inverted Promise.all fulfills with the first obtained result or rejects with the list of errors
const invert = p => new Promise((res, rej) => p.then(rej, res)) const invert = p => new Promise((res, rej) => p.then(rej, res))
@@ -186,7 +174,6 @@ module.exports = {
isSameTransactionError, isSameTransactionError,
isInsufficientBalanceError, isInsufficientBalanceError,
isNonceError, isNonceError,
isRevertError,
getRetrySequence, getRetrySequence,
promiseAny, promiseAny,
readAccessListFile, readAccessListFile,