From 3cf184c39185abd0ea87d935ebce3c3f7633c1e8 Mon Sep 17 00:00:00 2001 From: Kirill Fedoseev Date: Wed, 26 May 2021 21:58:20 +0700 Subject: [PATCH] Add statistics about used AMB information requests (#577) --- commons/message.js | 31 +++++++++++++++++++++- monitor/detectMediators.js | 48 +++++++++++++++++++++++++++++++---- monitor/getShortEventStats.js | 8 ++++-- monitor/utils/events.js | 23 +++++++++++++++++ monitor/utils/message.js | 16 ++++++++++++ oracle-e2e/test/amb.js | 21 ++------------- 6 files changed, 120 insertions(+), 27 deletions(-) diff --git a/commons/message.js b/commons/message.js index f1444fc5..43f10cea 100644 --- a/commons/message.js +++ b/commons/message.js @@ -1,3 +1,5 @@ +const { soliditySha3 } = require('web3-utils') + function strip0x(input) { return input.replace(/^0x/, '') } @@ -39,8 +41,35 @@ const normalizeAMBMessageEvent = e => { return parseAMBMessage(msgData) } +const ambInformationSignatures = [ + 'eth_call(address,bytes)', + 'eth_call(address,bytes,uint256)', + 'eth_call(address,address,uint256,bytes)', + 'eth_blockNumber()', + 'eth_getBlockByNumber()', + 'eth_getBlockByNumber(uint256)', + 'eth_getBlockByHash(bytes32)', + 'eth_getBalance(address)', + 'eth_getBalance(address,uint256)', + 'eth_getTransactionCount(address)', + 'eth_getTransactionCount(address,uint256)', + 'eth_getTransactionByHash(bytes32)', + 'eth_getTransactionReceipt(bytes32)', + 'eth_getStorageAt(address,bytes32)', + 'eth_getStorageAt(address,bytes32,uint256)' +] +const ambInformationSelectors = Object.fromEntries(ambInformationSignatures.map(sig => [soliditySha3(sig), sig])) +const normalizeAMBInfoRequest = e => ({ + messageId: e.returnValues.messageId, + sender: e.returnValues.sender, + requestSelector: ambInformationSelectors[e.returnValues.requestSelector] || 'unknown', + data: e.returnValues.data +}) + module.exports = { strip0x, parseAMBMessage, - normalizeAMBMessageEvent + normalizeAMBMessageEvent, + ambInformationSignatures, + normalizeAMBInfoRequest } diff --git a/monitor/detectMediators.js b/monitor/detectMediators.js index 01bf3d6f..4167147a 100644 --- a/monitor/detectMediators.js +++ b/monitor/detectMediators.js @@ -1,10 +1,9 @@ require('dotenv').config() const logger = require('./logger')('detectMediators.js') -const { isHomeContract, isForeignContract } = require('./utils/web3Cache') const eventsInfo = require('./utils/events') -const { getHomeTxSender, getForeignTxSender } = require('./utils/web3Cache') -const { addExecutionStatus } = require('./utils/message') -const { normalizeAMBMessageEvent } = require('../commons') +const { getHomeTxSender, getForeignTxSender, isHomeContract, isForeignContract } = require('./utils/web3Cache') +const { addExecutionStatus, addRetrievalStatus } = require('./utils/message') +const { normalizeAMBMessageEvent, normalizeAMBInfoRequest } = require('../commons') function countInteractions(requests) { const stats = {} @@ -30,6 +29,41 @@ function countInteractions(requests) { return stats } +function countInfoRequests(requests) { + const stats = {} + requests.forEach(msg => { + if (!stats[msg.sender]) { + stats[msg.sender] = {} + } + if (!stats[msg.sender][msg.requestSelector]) { + stats[msg.sender][msg.requestSelector] = { + callSucceeded: { + callbackSucceeded: 0, + callbackFailed: 0 + }, + callFailed: { + callbackSucceeded: 0, + callbackFailed: 0 + }, + pending: 0 + } + } + const stat = stats[msg.sender][msg.requestSelector] + if (msg.callStatus === true && msg.callbackStatus === true) { + stat.callSucceeded.callbackSucceeded += 1 + } else if (msg.callStatus === true && msg.callbackStatus === false) { + stat.callSucceeded.callbackFailed += 1 + } else if (msg.callStatus === false && msg.callbackStatus === true) { + stat.callFailed.callbackSucceeded += 1 + } else if (msg.callStatus === false && msg.callbackStatus === false) { + stat.callFailed.callbackFailed += 1 + } else { + stat.pending += 1 + } + }) + return stats +} + const normalize = event => ({ ...normalizeAMBMessageEvent(event), txHash: event.transactionHash, @@ -88,10 +122,13 @@ async function main(mode) { homeToForeignRequests, foreignToHomeRequests, homeToForeignConfirmations, - foreignToHomeConfirmations + foreignToHomeConfirmations, + informationRequests, + informationResponses } = await eventsInfo(mode) const homeToForeign = homeToForeignRequests.map(normalize).map(addExecutionStatus(homeToForeignConfirmations)) const foreignToHome = foreignToHomeRequests.map(normalize).map(addExecutionStatus(foreignToHomeConfirmations)) + const infoRequests = informationRequests.map(normalizeAMBInfoRequest).map(addRetrievalStatus(informationResponses)) for (const event of homeToForeign) { // AMB contract emits a single UserRequestForSignature event for every home->foreign request. @@ -146,6 +183,7 @@ async function main(mode) { floatingMediators, remotelyControlledMediators, unknown, + informationReceivers: countInfoRequests(infoRequests), lastChecked: Math.floor(Date.now() / 1000) } } diff --git a/monitor/getShortEventStats.js b/monitor/getShortEventStats.js index 1b6607ce..c2c568fc 100644 --- a/monitor/getShortEventStats.js +++ b/monitor/getShortEventStats.js @@ -21,7 +21,9 @@ async function main(bridgeMode, eventsInfo) { homeToForeignConfirmations, homeToForeignRequests, foreignToHomeConfirmations, - foreignToHomeRequests + foreignToHomeRequests, + informationRequests, + informationResponses } = eventsInfo if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) { @@ -34,7 +36,9 @@ async function main(bridgeMode, eventsInfo) { fromForeignToHomeDiff: foreignToHomeConfirmations.length - foreignToHomeRequests.length, home: { toForeign: homeToForeignRequests.length, - fromForeign: foreignToHomeConfirmations.length + fromForeign: foreignToHomeConfirmations.length, + informationRequests: informationRequests.length, + informationResponses: informationResponses.length }, foreign: { fromHome: homeToForeignConfirmations.length, diff --git a/monitor/utils/events.js b/monitor/utils/events.js index 812d0f11..e2bbdeff 100644 --- a/monitor/utils/events.js +++ b/monitor/utils/events.js @@ -129,6 +129,27 @@ async function main(mode) { })).map(normalizeEvent) foreignToHomeRequests = [...foreignToHomeRequests, ...foreignToHomeRequestsNew] + let informationRequests + let informationResponses + if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) { + logger.debug("calling homeBridge.getPastEvents('UserRequestForInformation')") + informationRequests = (await getPastEvents(homeBridge, { + event: 'UserRequestForInformation', + fromBlock: MONITOR_HOME_START_BLOCK, + toBlock: homeDelayedBlockNumber, + chain: 'home' + })).map(normalizeEvent) + + logger.debug("calling foreignBridge.getPastEvents('InformationRetrieved')") + informationResponses = (await getPastEvents(homeBridge, { + event: 'InformationRetrieved', + fromBlock: MONITOR_HOME_START_BLOCK, + toBlock: homeBlockNumber, + safeToBlock: homeDelayedBlockNumber, + chain: 'home' + })).map(normalizeEvent) + } + if (isExternalErc20) { logger.debug("calling erc20Contract.getPastEvents('Transfer')") let transferEvents = (await getPastEvents(erc20Contract, { @@ -225,6 +246,8 @@ async function main(mode) { homeToForeignConfirmations, foreignToHomeConfirmations, foreignToHomeRequests, + informationRequests, + informationResponses, isExternalErc20, bridgeMode, homeBlockNumber, diff --git a/monitor/utils/message.js b/monitor/utils/message.js index fed4c8d5..6fadf57e 100644 --- a/monitor/utils/message.js +++ b/monitor/utils/message.js @@ -28,6 +28,21 @@ function addExecutionStatus(processedList) { } } +function addRetrievalStatus(retrievedInfoList) { + const statuses = {} + retrievedInfoList.forEach(e => { + statuses[e.returnValues.messageId] = { + callStatus: e.returnValues.status, + callbackStatus: e.returnValues.callbackStatus + } + }) + return deliveredMsg => { + deliveredMsg.callStatus = statuses[deliveredMsg.messageId].callStatus + deliveredMsg.callbackStatus = statuses[deliveredMsg.messageId].callbackStatus + return deliveredMsg + } +} + /** * Normalizes the different event objects to facilitate data processing * @param {Object} event @@ -89,6 +104,7 @@ module.exports = { deliveredMsgNotProcessed, processedMsgNotDelivered, addExecutionStatus, + addRetrievalStatus, normalizeEventInformation, eventWithoutReference, unclaimedHomeToForeignRequests, diff --git a/oracle-e2e/test/amb.js b/oracle-e2e/test/amb.js index cecc1f53..b61d8ab5 100644 --- a/oracle-e2e/test/amb.js +++ b/oracle-e2e/test/amb.js @@ -2,7 +2,7 @@ const Web3 = require('web3') const assert = require('assert') 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 } = require('../../commons') +const { BOX_ABI, HOME_AMB_ABI, FOREIGN_AMB_ABI, ambInformationSignatures } = require('../../commons') const { delay, setRequiredSignatures } = require('./utils') const { toBN } = Web3.utils @@ -29,24 +29,7 @@ const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, amb.foreign, describe('arbitrary message bridging', () => { let requiredSignatures = 1 before(async () => { - const allowedMethods = [ - 'eth_call(address,bytes)', - 'eth_call(address,bytes,uint256)', - 'eth_call(address,address,uint256,bytes)', - 'eth_blockNumber()', - 'eth_getBlockByNumber()', - 'eth_getBlockByNumber(uint256)', - 'eth_getBlockByHash(bytes32)', - 'eth_getBalance(address)', - 'eth_getBalance(address,uint256)', - 'eth_getTransactionCount(address)', - 'eth_getTransactionCount(address,uint256)', - 'eth_getTransactionByHash(bytes32)', - 'eth_getTransactionReceipt(bytes32)', - 'eth_getStorageAt(address,bytes32)', - 'eth_getStorageAt(address,bytes32,uint256)' - ] - for (const method of allowedMethods) { + for (const method of ambInformationSignatures) { const selector = homeWeb3.utils.soliditySha3(method) await homeBridge.methods.enableAsyncRequestSelector(selector, true).send({ from: validator.address }) }