Async calls error codes (#587)
This commit is contained in:
parent
c92f80c484
commit
d53452675e
@ -19,6 +19,7 @@ COPY --from=contracts /mono/contracts/build ./contracts/build
|
||||
COPY commons/package.json ./commons/
|
||||
COPY oracle-e2e/package.json ./oracle-e2e/
|
||||
COPY monitor-e2e/package.json ./monitor-e2e/
|
||||
COPY oracle/src/utils/constants.js ./oracle/src/utils/constants.js
|
||||
|
||||
COPY yarn.lock .
|
||||
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
|
||||
|
@ -1,5 +1,6 @@
|
||||
const Web3 = require('web3')
|
||||
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 { uniformRetry } = require('../../e2e-commons/utils')
|
||||
const { BOX_ABI, HOME_AMB_ABI, FOREIGN_AMB_ABI, ambInformationSignatures } = require('../../commons')
|
||||
@ -264,7 +265,7 @@ describe('arbitrary message bridging', () => {
|
||||
await makeAsyncCall(selector, data2)
|
||||
|
||||
assert(!(await homeBox.methods.status().call()), 'status is true')
|
||||
assert.strictEqual(await homeBox.methods.data().call(), null, 'returned data is incorrect')
|
||||
assert.strictEqual(await homeBox.methods.data().call(), ASYNC_CALL_ERRORS.REVERT, 'returned data is incorrect')
|
||||
|
||||
const data3 = homeWeb3.eth.abi.encodeParameters(
|
||||
['address', 'address', 'uint256', 'bytes'],
|
||||
@ -274,7 +275,7 @@ describe('arbitrary message bridging', () => {
|
||||
await makeAsyncCall(selector, data3)
|
||||
|
||||
assert(!(await homeBox.methods.status().call()), 'status is true')
|
||||
assert.strictEqual(await homeBox.methods.data().call(), null, 'returned data is incorrect')
|
||||
assert.strictEqual(await homeBox.methods.data().call(), ASYNC_CALL_ERRORS.REVERT, 'returned data is incorrect')
|
||||
})
|
||||
|
||||
it('should make async eth_call for specific block', async () => {
|
||||
@ -315,6 +316,11 @@ describe('arbitrary message bridging', () => {
|
||||
await makeAsyncCall(selector, data3)
|
||||
|
||||
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 () => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
const { toBN } = require('web3').utils
|
||||
|
||||
const { zipToObject } = require('../../../utils/utils')
|
||||
const { ASYNC_CALL_ERRORS, ASYNC_ETH_CALL_MAX_GAS_LIMIT } = require('../../../utils/constants')
|
||||
const { zipToObject, isRevertError } = require('../../../utils/utils')
|
||||
|
||||
const argTypes = {
|
||||
to: 'address',
|
||||
@ -17,14 +18,23 @@ function makeCall(argNames) {
|
||||
const { blockNumber, ...opts } = zipToObject(argNames, args)
|
||||
|
||||
if (blockNumber && toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||
return [false, '0x']
|
||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
||||
}
|
||||
|
||||
const [status, result] = await web3.eth
|
||||
.call(opts, blockNumber || foreignBlock.number)
|
||||
.then(result => [true, result], err => [false, err.data])
|
||||
// different clients might use different default gas limits, so it makes sense to limit it by some large number
|
||||
if (!opts.gas || toBN(opts.gas).gt(toBN(ASYNC_ETH_CALL_MAX_GAS_LIMIT))) {
|
||||
opts.gas = ASYNC_ETH_CALL_MAX_GAS_LIMIT
|
||||
}
|
||||
|
||||
return [status, web3.eth.abi.encodeParameter('bytes', result)]
|
||||
return web3.eth
|
||||
.call(opts, blockNumber || foreignBlock.number)
|
||||
.then(result => [true, web3.eth.abi.encodeParameter('bytes', result)])
|
||||
.catch(e => {
|
||||
if (isRevertError(e)) {
|
||||
return [false, ASYNC_CALL_ERRORS.REVERT]
|
||||
}
|
||||
throw e
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
const { toBN } = require('web3').utils
|
||||
|
||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
||||
|
||||
async function call(web3, data, foreignBlock) {
|
||||
const address = web3.eth.abi.decodeParameter('address', data)
|
||||
|
||||
@ -12,7 +14,7 @@ async function callArchive(web3, data, foreignBlock) {
|
||||
const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
|
||||
|
||||
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||
return [false, '0x']
|
||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
||||
}
|
||||
|
||||
const balance = await web3.eth.getBalance(address, blockNumber)
|
||||
|
@ -1,3 +1,4 @@
|
||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
||||
const { serializeBlock } = require('./serializers')
|
||||
|
||||
async function call(web3, data, foreignBlock) {
|
||||
@ -6,7 +7,7 @@ async function call(web3, data, foreignBlock) {
|
||||
const block = await web3.eth.getBlock(blockHash)
|
||||
|
||||
if (block === null || block.number > foreignBlock.number) {
|
||||
return [false, '0x']
|
||||
return [false, ASYNC_CALL_ERRORS.NOT_FOUND]
|
||||
}
|
||||
|
||||
return [true, serializeBlock(web3, block)]
|
||||
|
@ -1,12 +1,13 @@
|
||||
const { toBN } = require('web3').utils
|
||||
|
||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
||||
const { serializeBlock } = require('./serializers')
|
||||
|
||||
async function call(web3, data, foreignBlock) {
|
||||
const blockNumber = web3.eth.abi.decodeParameter('uint256', data)
|
||||
|
||||
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||
return [false, '0x']
|
||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
||||
}
|
||||
|
||||
const block = await web3.eth.getBlock(blockNumber)
|
||||
|
@ -1,5 +1,7 @@
|
||||
const { toBN } = require('web3').utils
|
||||
|
||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
||||
|
||||
async function call(web3, data, foreignBlock) {
|
||||
const { 0: address, 1: slot } = web3.eth.abi.decodeParameters(['address', 'bytes32'], data)
|
||||
|
||||
@ -12,7 +14,7 @@ async function callArchive(web3, data, foreignBlock) {
|
||||
const { 0: address, 1: slot, 2: blockNumber } = web3.eth.abi.decodeParameters(['address', 'bytes32', 'uint256'], data)
|
||||
|
||||
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||
return [false, '0x']
|
||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
||||
}
|
||||
|
||||
const value = await web3.eth.getStorageAt(address, slot, blockNumber)
|
||||
|
@ -1,3 +1,4 @@
|
||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
||||
const { serializeTx } = require('./serializers')
|
||||
|
||||
async function call(web3, data, foreignBlock) {
|
||||
@ -6,7 +7,7 @@ async function call(web3, data, foreignBlock) {
|
||||
const tx = await web3.eth.getTransaction(hash)
|
||||
|
||||
if (tx === null || tx.blockNumber > foreignBlock.number) {
|
||||
return [false, '0x']
|
||||
return [false, ASYNC_CALL_ERRORS.NOT_FOUND]
|
||||
}
|
||||
|
||||
return [true, serializeTx(web3, tx)]
|
||||
|
@ -1,5 +1,7 @@
|
||||
const { toBN } = require('web3').utils
|
||||
|
||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
||||
|
||||
async function call(web3, data, foreignBlock) {
|
||||
const address = web3.eth.abi.decodeParameter('address', data)
|
||||
|
||||
@ -12,7 +14,7 @@ async function callArchive(web3, data, foreignBlock) {
|
||||
const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
|
||||
|
||||
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||
return [false, '0x']
|
||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
||||
}
|
||||
|
||||
const nonce = await web3.eth.getTransactionCount(address, blockNumber)
|
||||
|
@ -1,3 +1,4 @@
|
||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
||||
const { serializeReceipt } = require('./serializers')
|
||||
|
||||
async function call(web3, data, foreignBlock) {
|
||||
@ -6,7 +7,7 @@ async function call(web3, data, foreignBlock) {
|
||||
const receipt = await web3.eth.getTransactionReceipt(hash)
|
||||
|
||||
if (receipt === null || receipt.blockNumber > foreignBlock.number) {
|
||||
return [false, '0x']
|
||||
return [false, ASYNC_CALL_ERRORS.NOT_FOUND]
|
||||
}
|
||||
|
||||
return [true, serializeReceipt(web3, receipt)]
|
||||
|
@ -4,7 +4,13 @@ const { soliditySha3 } = require('web3').utils
|
||||
const { HttpListProviderError } = require('../../services/HttpListProvider')
|
||||
const rootLogger = require('../../services/logger')
|
||||
const makeBlockFinder = require('../../services/blockFinder')
|
||||
const { EXIT_CODES, MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/constants')
|
||||
const {
|
||||
EXIT_CODES,
|
||||
MAX_CONCURRENT_EVENTS,
|
||||
EXTRA_GAS_ABSOLUTE,
|
||||
ASYNC_CALL_ERRORS,
|
||||
MAX_ASYNC_CALL_RESULT_LENGTH
|
||||
} = require('../../utils/constants')
|
||||
const estimateGas = require('./estimateGas')
|
||||
const { getValidatorContract, getBlock, getBlockNumber, getRequiredBlockConfirmations } = require('../../tx/web3')
|
||||
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
||||
@ -79,12 +85,17 @@ function processInformationRequestsBuilder(config) {
|
||||
logger.info({ requestSelector, method: asyncCallMethod, data }, 'Processing async request')
|
||||
|
||||
const call = asyncCalls[asyncCallMethod]
|
||||
const [status, result] = await call(web3ForeignArchive, data, foreignClosestBlock).catch(e => {
|
||||
let [status, result] = await call(web3ForeignArchive, data, foreignClosestBlock).catch(e => {
|
||||
if (e instanceof HttpListProviderError) {
|
||||
throw e
|
||||
}
|
||||
return [false, '0x']
|
||||
logger.error({ error: e.message }, 'Unknown error during async call execution')
|
||||
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')
|
||||
|
||||
let gasEstimate
|
||||
|
@ -27,5 +27,17 @@ module.exports = {
|
||||
FALLBACK_RPC_URL_SWITCH_TIMEOUT: 60 * 60 * 1000,
|
||||
SENDER_QUEUE_MAX_PRIORITY: 10,
|
||||
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
|
||||
}
|
||||
|
@ -123,6 +123,18 @@ 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
|
||||
// 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))
|
||||
@ -174,6 +186,7 @@ module.exports = {
|
||||
isSameTransactionError,
|
||||
isInsufficientBalanceError,
|
||||
isNonceError,
|
||||
isRevertError,
|
||||
getRetrySequence,
|
||||
promiseAny,
|
||||
readAccessListFile,
|
||||
|
Loading…
Reference in New Issue
Block a user