Use requestGasLimit parameter in AMB oracle in estimateGas (#415)

This commit is contained in:
Kirill Fedoseev 2020-08-06 20:15:51 +07:00 committed by GitHub
parent 8a42cfbe2b
commit 1eb8a8b1dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 94 additions and 12 deletions

@ -7,7 +7,7 @@ const rpcUrlsManager = require('./services/getRpcUrlsManager')
const { getNonce, getChainId, getEventsFromTx } = require('./tx/web3')
const { sendTx } = require('./tx/sendTx')
const { checkHTTPS, watchdog, syncForEach, addExtraGas } = require('./utils/utils')
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE } = require('./utils/constants')
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
const { ORACLE_VALIDATOR_ADDRESS, ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, ORACLE_ALLOW_HTTP_FOR_RPC } = process.env
@ -143,7 +143,12 @@ async function sendJobTx(jobs) {
let nonce = await getNonce(web3Instance, ORACLE_VALIDATOR_ADDRESS)
await syncForEach(jobs, async job => {
const gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE)
let gasLimit
if (typeof job.extraGas === 'number') {
gasLimit = addExtraGas(job.gasEstimate + job.extraGas, 0, MAX_GAS_LIMIT)
} else {
gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT)
}
try {
logger.info(`Sending transaction with nonce ${nonce}`)

@ -3,14 +3,23 @@ const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = req
const logger = require('../../services/logger').child({
module: 'processAffirmationRequests:estimateGas'
})
const { parseAMBHeader } = require('../../utils/message')
const { strip0x } = require('../../../../commons')
const {
AMB_AFFIRMATION_REQUEST_EXTRA_GAS_ESTIMATOR: estimateExtraGas,
MIN_AMB_HEADER_LENGTH
} = require('../../utils/constants')
async function estimateGas({ web3, homeBridge, validatorContract, message, address }) {
try {
const gasEstimate = await homeBridge.methods.executeAffirmation(message).estimateGas({
from: address
})
const msgGasLimit = parseAMBHeader(message).gasLimit
// message length in bytes
const len = strip0x(message).length / 2 - MIN_AMB_HEADER_LENGTH
return gasEstimate
return gasEstimate + msgGasLimit + estimateExtraGas(len)
} catch (e) {
if (e instanceof HttpListProviderError) {
throw e

@ -4,7 +4,7 @@ const promiseLimit = require('promise-limit')
const rootLogger = require('../../services/logger')
const { web3Home } = require('../../services/web3')
const bridgeValidatorsABI = require('../../../../contracts/build/contracts/BridgeValidators').abi
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
const { EXIT_CODES, MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/constants')
const estimateGas = require('./estimateGas')
const { parseAMBMessage } = require('../../../../commons')
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
@ -75,6 +75,7 @@ function processAffirmationRequestsBuilder(config) {
txToSend.push({
data,
gasEstimate,
extraGas: EXTRA_GAS_ABSOLUTE,
transactionReference: affirmationRequest.transactionHash,
to: config.homeBridgeAddress
})

@ -4,6 +4,7 @@ const { AlreadyProcessedError, IncompatibleContractError, InvalidValidatorError
const logger = require('../../services/logger').child({
module: 'processCollectedSignatures:estimateGas'
})
const { parseAMBHeader } = require('../../utils/message')
const web3 = new Web3()
const { toBN } = Web3.utils
@ -24,7 +25,12 @@ async function estimateGas({
const gasEstimate = await foreignBridge.methods.executeSignatures(message, signatures).estimateGas({
from: address
})
return gasEstimate
const msgGasLimit = parseAMBHeader(message).gasLimit
// + estimateExtraGas(len)
// is not needed here, since estimateGas will already take into account gas
// needed for memory expansion, message processing, etc.
return gasEstimate + msgGasLimit
} catch (e) {
if (e instanceof HttpListProviderError) {
throw e

@ -8,7 +8,7 @@ const { signatureToVRS, packSignatures } = require('../../utils/message')
const { parseAMBMessage } = require('../../../../commons')
const estimateGas = require('./estimateGas')
const { AlreadyProcessedError, IncompatibleContractError, InvalidValidatorError } = require('../../utils/errors')
const { MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
const { MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/constants')
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
@ -107,6 +107,7 @@ function processCollectedSignaturesBuilder(config) {
txToSend.push({
data,
gasEstimate,
extraGas: EXTRA_GAS_ABSOLUTE,
transactionReference: colSignature.transactionHash,
to: config.foreignBridgeAddress
})

@ -16,7 +16,7 @@ const {
watchdog,
nonceError
} = require('./utils/utils')
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE } = require('./utils/constants')
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
const { ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY } = process.env
@ -106,7 +106,12 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry }) {
logger.debug(`Sending ${txArray.length} transactions`)
await syncForEach(txArray, async job => {
const gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE)
let gasLimit
if (typeof job.extraGas === 'number') {
gasLimit = addExtraGas(job.gasEstimate + job.extraGas, 0, MAX_GAS_LIMIT)
} else {
gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT)
}
try {
logger.info(`Sending transaction with nonce ${nonce}`)

@ -1,5 +1,9 @@
module.exports = {
EXTRA_GAS_PERCENTAGE: 4,
EXTRA_GAS_ABSOLUTE: 200000,
AMB_AFFIRMATION_REQUEST_EXTRA_GAS_ESTIMATOR: len => Math.floor(0.0035 * len ** 2 + 40 * len),
MIN_AMB_HEADER_LENGTH: 32 + 20 + 20 + 4 + 2 + 1 + 2,
MAX_GAS_LIMIT: 10000000,
MAX_CONCURRENT_EVENTS: 50,
RETRY_CONFIG: {
retries: 20,

@ -73,9 +73,37 @@ function packSignatures(array) {
return `0x${msgLength}${v}${r}${s}`
}
function parseAMBHeader(message) {
message = strip0x(message)
const messageIdStart = 0
const messageIdLength = 32 * 2
const messageId = `0x${message.slice(messageIdStart, messageIdStart + messageIdLength)}`
const senderStart = messageIdStart + messageIdLength
const senderLength = 20 * 2
const sender = `0x${message.slice(senderStart, senderStart + senderLength)}`
const executorStart = senderStart + senderLength
const executorLength = 20 * 2
const executor = `0x${message.slice(executorStart, executorStart + executorLength)}`
const gasLimitStart = executorStart + executorLength
const gasLimitLength = 4 * 2
const gasLimit = parseInt(message.slice(gasLimitStart, gasLimitStart + gasLimitLength), 16)
return {
messageId,
sender,
executor,
gasLimit
}
}
module.exports = {
createMessage,
parseMessage,
signatureToVRS,
packSignatures
packSignatures,
parseAMBHeader
}

@ -48,13 +48,13 @@ async function waitForFunds(web3, address, minimumBalance, cb, logger) {
)
}
function addExtraGas(gas, extraPercentage) {
function addExtraGas(gas, extraPercentage, maxGasLimit = Infinity) {
gas = BigNumber(gas)
extraPercentage = BigNumber(1 + extraPercentage)
const gasWithExtra = gas.multipliedBy(extraPercentage).toFixed(0)
return BigNumber(gasWithExtra)
return BigNumber.min(maxGasLimit, gasWithExtra)
}
function setIntervalAndRun(f, interval) {

@ -1,6 +1,6 @@
const { BN, toBN } = require('web3').utils
const { expect } = require('chai').use(require('bn-chai')(BN))
const { createMessage, parseMessage, signatureToVRS } = require('../src/utils/message')
const { createMessage, parseMessage, signatureToVRS, parseAMBHeader } = require('../src/utils/message')
describe('message utils', () => {
const expectedMessageLength = 104
@ -288,4 +288,19 @@ describe('message utils', () => {
expect(signatureThunk).to.throw()
})
})
describe('parseAMBHeader', () => {
it('should return correct values for parsed headers', () => {
// given
const message =
'0x000500009a6ff99b356dd998260582be7d95a4d08b2132600000000000000061339d0e6f308a410f18888932bdf661636a0f538f34718200957aeadd6bece186e61b95618e73a6dc000f42400101002a4d2fb102cf00000000000000000000000081c770bbe8f5f41b4642ed575e630c911c94e4070000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002e516d543162324178466b6643456a6f715861547148734370666f724a4c66765667434853516e513847575a347662000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d5a7543586f693378487338486e4c325a423539316674466f4c454471516b473655746e47324d6d513147614e000000000000000000000000000000000000'
const { messageId, sender, executor, gasLimit } = parseAMBHeader(message)
// then
expect(messageId).to.equal('0x000500009a6ff99b356dd998260582be7d95a4d08b2132600000000000000061')
expect(sender).to.equal('0x339d0e6f308a410f18888932bdf661636a0f538f')
expect(executor).to.equal('0x34718200957aeadd6bece186e61b95618e73a6dc')
expect(gasLimit).to.equal(1000000)
})
})
})

@ -34,6 +34,14 @@ describe('utils', () => {
expect(result.toString()).to.equal('225')
})
it('should handle maxGasLimit', () => {
const result1 = addExtraGas(new BigNumber(100), 0.25, 110)
const result2 = addExtraGas(new BigNumber(100), 0.25, 150)
expect(result1.toString()).to.equal('110')
expect(result2.toString()).to.equal('125')
})
})
describe('checkHTTPS', () => {