Skip to content

Commit

Permalink
Merge the develop branch to the master branch, preparation to v3.0.0
Browse files Browse the repository at this point in the history
This merge contains the following set of changes:
  * [Oracle, Improvement] Async calls error codes (#587)
  * [Oracle, Improvement] Refactor/async call serializers (#588)
  • Loading branch information
akolotov authored Jul 16, 2021
2 parents c92f80c + 4c06329 commit 4f5e3c4
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 79 deletions.
1 change: 1 addition & 0 deletions Dockerfile.e2e
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
119 changes: 67 additions & 52 deletions oracle-e2e/test/amb.js
Original file line number Diff line number Diff line change
@@ -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')
Expand All @@ -26,6 +27,45 @@ const foreignBox = new foreignWeb3.eth.Contract(BOX_ABI, amb.foreignBox, opts)
const homeBridge = new homeWeb3.eth.Contract(HOME_AMB_ABI, amb.home, opts)
const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, amb.foreign, opts)

function validateBlock(web3, serialized, block) {
assert.strictEqual(serialized.length, 2 + 64 * 12)
const values = web3.eth.abi.decodeParameter(
'(uint256,bytes32,address,uint256,uint256,bytes32,bytes32,bytes32,bytes32,uint256,uint256,uint256)',
serialized
)
assert.strictEqual(values[0], block.number.toString(), 'wrong block number returned')
assert.strictEqual(values[1], block.hash, 'wrong block hash returned')
assert.strictEqual(values[2], block.miner, 'wrong block miner returned')
assert.strictEqual(values[3], block.gasUsed.toString(), 'wrong block gasUsed returned')
assert.strictEqual(values[4], block.gasLimit.toString(), 'wrong block gasLimit returned')
assert.strictEqual(values[5], block.parentHash, 'wrong block parentHash returned')
assert.strictEqual(values[6], block.receiptsRoot, 'wrong block receiptsRoot returned')
assert.strictEqual(values[7], block.stateRoot, 'wrong block stateRoot returned')
assert.strictEqual(values[8], block.transactionsRoot, 'wrong block transactionsRoot returned')
assert.strictEqual(values[9], block.timestamp.toString(), 'wrong block timestamp returned')
assert.strictEqual(values[10], block.difficulty, 'wrong block difficulty returned')
assert.strictEqual(values[11], block.totalDifficulty, 'wrong block totalDifficulty returned')
}

function validateTransaction(web3, serialized, tx) {
assert.strictEqual(serialized.length, 64 * 13 + tx.input.length + 56)
const values = web3.eth.abi.decodeParameter(
'(bytes32,uint256,bytes32,uint256,address,address,uint256,uint256,uint256,uint256,bytes)',
serialized
)
assert.strictEqual(values[0], tx.hash, 'wrong txHash returned')
assert.strictEqual(values[1], tx.blockNumber.toString(), 'wrong tx blockNumber returned')
assert.strictEqual(values[2], tx.blockHash.toString(), 'wrong tx blockHash returned')
assert.strictEqual(values[3], tx.transactionIndex.toString(), 'wrong tx transactionIndex returned')
assert.strictEqual(values[4], tx.from, 'wrong tx from returned')
assert.strictEqual(values[5], tx.to, 'wrong tx to returned')
assert.strictEqual(values[6], tx.value, 'wrong tx value returned')
assert.strictEqual(values[7], tx.nonce.toString(), 'wrong tx nonce returned')
assert.strictEqual(values[8], tx.gas.toString(), 'wrong tx gas returned')
assert.strictEqual(values[9], tx.gasPrice, 'wrong tx gasPrice returned')
assert.strictEqual(values[10], tx.input, 'wrong tx data returned')
}

describe('arbitrary message bridging', () => {
let requiredSignatures = 1
before(async () => {
Expand Down Expand Up @@ -264,7 +304,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'],
Expand All @@ -274,7 +314,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 () => {
Expand Down Expand Up @@ -315,6 +355,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 () => {
Expand All @@ -334,15 +379,8 @@ describe('arbitrary message bridging', () => {

assert(await homeBox.methods.status().call(), 'status is false')
const data = await homeBox.methods.data().call()
assert.strictEqual(data.length, 2 + 64 * 3)
const { 0: number, 1: hash, 2: miner } = homeWeb3.eth.abi.decodeParameters(
['uint256', 'bytes32', 'address'],
data
)
const block = await foreignWeb3.eth.getBlock(blockNumber)
assert.strictEqual(number, blockNumber, 'wrong block number returned')
assert.strictEqual(hash, block.hash, 'wrong block hash returned')
assert.strictEqual(miner, block.miner, 'wrong block miner returned')
validateBlock(homeWeb3, data, block)
})

it('should make async eth_getBlockByNumber and return latest block', async () => {
Expand All @@ -352,7 +390,7 @@ describe('arbitrary message bridging', () => {

assert(await homeBox.methods.status().call(), 'status is false')
const data = await homeBox.methods.data().call()
assert.strictEqual(data.length, 2 + 64 * 3)
assert.strictEqual(data.length, 2 + 64 * 12)
})

it('should make async eth_getBlockByHash', async () => {
Expand All @@ -364,16 +402,7 @@ describe('arbitrary message bridging', () => {

assert(await homeBox.methods.status().call(), 'status is false')
const data = await homeBox.methods.data().call()
assert.strictEqual(data.length, 2 + 64 * 3)

const { 0: number, 1: hash, 2: miner } = homeWeb3.eth.abi.decodeParameters(
['uint256', 'bytes32', 'address'],
data
)

assert.strictEqual(number, blockNumber, 'wrong block number returned')
assert.strictEqual(hash, block.hash, 'wrong block hash returned')
assert.strictEqual(miner, block.miner, 'wrong block miner returned')
validateBlock(homeWeb3, data, block)
})

it('should make async eth_getBalance', async () => {
Expand Down Expand Up @@ -469,28 +498,7 @@ describe('arbitrary message bridging', () => {

assert(await homeBox.methods.status().call(), 'status is false')
const data = await homeBox.methods.data().call()
const dataTypes = [
'bytes32',
'uint256',
'address',
'address',
'uint256',
'uint256',
'uint256',
'uint256',
'bytes'
]
const values = homeWeb3.eth.abi.decodeParameters(dataTypes, data)

assert.strictEqual(values[0], txHash, 'wrong txHash returned')
assert.strictEqual(values[1], tx.blockNumber.toString(), 'wrong tx blockNumber returned')
assert.strictEqual(values[2], tx.from, 'wrong tx from returned')
assert.strictEqual(values[3], tx.to, 'wrong tx to returned')
assert.strictEqual(values[4], tx.value, 'wrong tx value returned')
assert.strictEqual(values[5], tx.nonce.toString(), 'wrong tx nonce returned')
assert.strictEqual(values[6], tx.gas.toString(), 'wrong tx gas returned')
assert.strictEqual(values[7], tx.gasPrice, 'wrong tx gasPrice returned')
assert.strictEqual(values[8], tx.input, 'wrong tx data returned')
validateTransaction(homeWeb3, data, tx)
})

it('should make async eth_getTransactionReceipt', async () => {
Expand All @@ -502,18 +510,25 @@ describe('arbitrary message bridging', () => {

assert(await homeBox.methods.status().call(), 'status is false')
const data = await homeBox.methods.data().call()
const dataTypes = ['bytes32', 'uint256', 'bool', '(address,bytes32[],bytes)[]']
const values = homeWeb3.eth.abi.decodeParameters(dataTypes, data)
const values = homeWeb3.eth.abi.decodeParameter(
'(bytes32,uint256,bytes32,uint256,address,address,uint256,bool,(address,bytes32[],bytes)[])',
data
)

assert.strictEqual(values[0], txHash, 'wrong txHash returned')
assert.strictEqual(values[1], receipt.blockNumber.toString(), 'wrong tx blockNumber returned')
assert.strictEqual(values[2], receipt.status, 'wrong tx status returned')
assert.strictEqual(values[3].length, 1, 'wrong logs length returned')
assert.strictEqual(values[3][0][0], receipt.logs[0].address, 'wrong log address returned')
assert.strictEqual(values[3][0][1].length, 2, 'wrong log topics length returned')
assert.strictEqual(values[3][0][1][0], receipt.logs[0].topics[0], 'wrong event signature returned')
assert.strictEqual(values[3][0][1][1], receipt.logs[0].topics[1], 'wrong message id returned')
assert.strictEqual(values[3][0][2], receipt.logs[0].data, 'wrong log data returned')
assert.strictEqual(values[2], receipt.blockHash, 'wrong tx blockHash returned')
assert.strictEqual(values[3], receipt.transactionIndex.toString(), 'wrong tx transactionIndex returned')
assert.strictEqual(values[4].toLowerCase(), receipt.from, 'wrong tx from returned')
assert.strictEqual(values[5].toLowerCase(), receipt.to, 'wrong tx to returned')
assert.strictEqual(values[6], receipt.gasUsed.toString(), 'wrong gasUsed to returned')
assert.strictEqual(values[7], receipt.status, 'wrong tx status returned')
assert.strictEqual(values[8].length, 1, 'wrong logs length returned')
assert.strictEqual(values[8][0][0], receipt.logs[0].address, 'wrong log address returned')
assert.strictEqual(values[8][0][1].length, 2, 'wrong log topics length returned')
assert.strictEqual(values[8][0][1][0], receipt.logs[0].topics[0], 'wrong event signature returned')
assert.strictEqual(values[8][0][1][1], receipt.logs[0].topics[1], 'wrong message id returned')
assert.strictEqual(values[8][0][2], receipt.logs[0].data, 'wrong log data returned')
})

it('should make async eth_getStorageAt', async () => {
Expand Down
22 changes: 16 additions & 6 deletions oracle/src/events/processAMBInformationRequests/calls/ethCall.js
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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
})
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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)

Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
const { serializeBlock } = require('./serializers')

async function call(web3, data, foreignBlock) {
Expand All @@ -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)]
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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)

Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
const { serializeTx } = require('./serializers')

async function call(web3, data, foreignBlock) {
Expand All @@ -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)]
Expand Down
Original file line number Diff line number Diff line change
@@ -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)

Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
const { serializeReceipt } = require('./serializers')

async function call(web3, data, foreignBlock) {
Expand All @@ -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)]
Expand Down
Loading

0 comments on commit 4f5e3c4

Please sign in to comment.