From b223845599b170eeaaba4e1b5e1464754767d2b7 Mon Sep 17 00:00:00 2001 From: Leon Prouger Date: Mon, 6 Jul 2020 21:22:52 +0300 Subject: [PATCH 1/9] Adding method to look for unrelayed CollectedSigs --- native-to-erc20/oracle/src/utils/cycle.js | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 native-to-erc20/oracle/src/utils/cycle.js diff --git a/native-to-erc20/oracle/src/utils/cycle.js b/native-to-erc20/oracle/src/utils/cycle.js new file mode 100644 index 0000000..fb3864f --- /dev/null +++ b/native-to-erc20/oracle/src/utils/cycle.js @@ -0,0 +1,46 @@ +const { getEvents } = require('../tx/web3') +const config = require('../../config/collected-signatures-watcher.config') +const { web3Home, web3Foreign } = require('../services/web3') +const { parseMessage } = require('../utils/message') + +const getMissedCycles = async () => { + +} + +const getCollectedSignatures = async ({ fromBlock, toBlock }) => { + + const homeBridge = new web3Home.eth.Contract(config.eventAbi, config.homeBridgeAddress) + const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress) + + + // config.homeBridgeAddress, + // config.foreignBridgeAddress, + const events = await getEvents({ + contract: homeBridge, + event: config.event, + fromBlock, + toBlock, + filter: config.eventFilter + }) + console.log(events.length) + for (const event of events) { + const { messageHash } = event.returnValues + const message = parseMessage(await homeBridge.methods.message(messageHash).call()) + const isRelayed = await foreignBridge.methods.relayedMessages(message.txHash).call() + console.log(isRelayed) + if (!isRelayed) { + const { blockNumber, transactionHash } = event + console.log({ blockNumber, transactionHash }) + } + } + + // const contract + return events +} + +getCollectedSignatures({ fromBlock: 4850326, toBlock: 5050326 }) + +module.exports = { + getMissedCycles, + getCollectedSignatures +} From 5614e97dde75fee6eeac5e54e7fc25a2683550e5 Mon Sep 17 00:00:00 2001 From: Leon Prouger Date: Wed, 8 Jul 2020 14:53:23 +0300 Subject: [PATCH 2/9] adding a function to relay messages --- native-to-erc20/contracts/signatures.md | 14 ++ .../processCollectedSignatures/createRawTx.js | 78 +++++++++ native-to-erc20/oracle/src/tx/cycle.js | 155 ++++++++++++++++++ native-to-erc20/oracle/src/utils/cycle.js | 46 ------ 4 files changed, 247 insertions(+), 46 deletions(-) create mode 100644 native-to-erc20/contracts/signatures.md create mode 100644 native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js create mode 100644 native-to-erc20/oracle/src/tx/cycle.js delete mode 100644 native-to-erc20/oracle/src/utils/cycle.js diff --git a/native-to-erc20/contracts/signatures.md b/native-to-erc20/contracts/signatures.md new file mode 100644 index 0000000..79ea9d4 --- /dev/null +++ b/native-to-erc20/contracts/signatures.md @@ -0,0 +1,14 @@ +# Function signatures +executeSignatures(uint8[],bytes32[],bytes32[],bytes): 0x232a2c1d + +submitSignature(bytes signature, bytes message): 0x630cea8e + +submitSignatureOfMessageWithUnknownLength(bytes,bytes): 0x9b5a5489 + + +# Event signatures + +CollectedSignatures(address,bytes32,uint256): 0x41555740 + + +done using: https://piyolab.github.io/playground/ethereum/getEncodedFunctionSignature/ diff --git a/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js b/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js new file mode 100644 index 0000000..05cc341 --- /dev/null +++ b/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js @@ -0,0 +1,78 @@ +const { HttpListProviderError } = require('http-list-provider') +const { signatureToVRS } = require('../../utils/message') +const estimateGas = require('./estimateGas') +const { + AlreadyProcessedError, + IncompatibleContractError, + InvalidValidatorError +} = require('../../utils/errors') + +const createRawTx = async ({ homeBridge, foreignBridge, logger, colSignature, foreignValidatorContract }) => { + const { messageHash, NumberOfCollectedSignatures } = colSignature.returnValues + + logger.info(`Processing CollectedSignatures ${colSignature.transactionHash}`) + const message = await homeBridge.methods.message(messageHash).call() + const expectedMessageLength = await homeBridge.methods.requiredMessageLength().call() + + const requiredSignatures = [] + requiredSignatures.length = NumberOfCollectedSignatures + requiredSignatures.fill(0) + + const [v, r, s] = [[], [], []] + logger.debug('Getting message signatures') + const signaturePromises = requiredSignatures.map(async (el, index) => { + logger.debug({ index }, 'Getting message signature') + const signature = await homeBridge.methods.signature(messageHash, index).call() + const recover = signatureToVRS(signature) + v.push(recover.v) + r.push(recover.r) + s.push(recover.s) + }) + + await Promise.all(signaturePromises) + + let gasEstimate, methodName + try { + logger.debug('Estimate gas') + const result = await estimateGas({ + foreignBridge, + validatorContract: foreignValidatorContract, + v, + r, + s, + message, + numberOfCollectedSignatures: NumberOfCollectedSignatures, + expectedMessageLength + }) + logger.info({ result }, 'Gas estimated') + gasEstimate = result.gasEstimate + methodName = result.methodName + } catch (e) { + if (e instanceof HttpListProviderError) { + throw new Error( + 'RPC Connection Error: submitSignature Gas Estimate cannot be obtained.' + ) + } else if (e instanceof AlreadyProcessedError) { + logger.info(`Already processed CollectedSignatures ${colSignature.transactionHash}`) + return + } else if ( + e instanceof IncompatibleContractError || + e instanceof InvalidValidatorError + ) { + logger.error(`The message couldn't be processed; skipping: ${e.message}`) + return + } else { + logger.error(e, 'Unknown error while processing transaction') + throw e + } + } + const data = await foreignBridge.methods[methodName](v, r, s, message).encodeABI() + return { + data, + gasEstimate, + transactionReference: colSignature.transactionHash, + to: foreignBridge.options.address + } +} + +module.exports = createRawTx diff --git a/native-to-erc20/oracle/src/tx/cycle.js b/native-to-erc20/oracle/src/tx/cycle.js new file mode 100644 index 0000000..757f941 --- /dev/null +++ b/native-to-erc20/oracle/src/tx/cycle.js @@ -0,0 +1,155 @@ +const { getEvents } = require('./web3') +const config = require('../../config/collected-signatures-watcher.config') +const { web3Home, web3Foreign } = require('../services/web3') +const { sendTx } = require('./sendTx') +const { parseMessage, parseNewSetMessage } = require('../utils/message') +const createRawTx = require('../events/processCollectedSignatures/createRawTx') +const { getNonce, getChainId } = require('./web3') +const GasPrice = require('../services/gasPrice') +const { + addExtraGas, + privateKeyToAddress +} = require('../utils/utils') +const { EXTRA_GAS_PERCENTAGE } = require('../utils/constants') + +const foreignBridgeValidatorsABI = require('../../abis/ForeignBridgeValidators.abi') +const rootLogger = require('../services/logger') + +const { VALIDATOR_ADDRESS_PRIVATE_KEY } = process.env + +const isNewSet = (message) => !!message.newSet +const isNotNewSet = (message) => !isNewSet(message) + +const isLengthExpected = (unparsedMessage, expectedMessageLength) => unparsedMessage.length === 2 + 2 * expectedMessageLength + +const parseGenericMessage = (unparsedMessage, expectedMessageLength) => { + if (isLengthExpected(unparsedMessage, expectedMessageLength)) { + return parseMessage(unparsedMessage) + } else { + return parseNewSetMessage(unparsedMessage, expectedMessageLength) + } +} + +const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter }) => { + console.log({ fromBlock, toBlock, isRelayedFilter }) + const homeBridge = new web3Home.eth.Contract(config.eventAbi, config.homeBridgeAddress) + + const expectedMessageLength = await homeBridge.methods.requiredMessageLength().call() + + const events = await getEvents({ + contract: homeBridge, + event: config.event, + fromBlock, + toBlock, + filter: config.eventFilter + }) + + let messages = [] + for (const event of events) { + const { messageHash } = event.returnValues + const unparsedMessage = await homeBridge.methods.message(messageHash).call() + const message = parseGenericMessage(unparsedMessage, expectedMessageLength) + // console.log({ unparsedMessage }) + message.event = event + messages.push(message) + } + + if (typeof isNewSetFilter !== 'undefined') { + const messageFilter = isNewSetFilter ? isNewSet : isNotNewSet + messages = messages.filter(messageFilter) + } + + console.log({ numberOfMessages: messages.length }) + + if (typeof isRelayedFilter === 'undefined') { + messages.forEach(message => { + console.log({ + message + }) + }) + return messages + } + + const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress) + const filteredMessages = [] + for (const message of messages) { + const isRelayed = await foreignBridge.methods.relayedMessages(message.txHash).call() + if (isRelayed === isRelayedFilter) { + filteredMessages.push(message) + } + } + + console.log({ numberOfFilteredMessages: filteredMessages.length }) + console.log('filtered messages:') + filteredMessages.forEach(message => { + console.log({ + message + }) + }) + + return filteredMessages +} + +const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limit, skip }) => { + const messages = (await getMessages({ fromBlock, toBlock, isNewSetFilter, isRelayedFilter: false })).slice(0, limit) + console.log({ messages }) + const homeBridge = new web3Home.eth.Contract(config.eventAbi, config.homeBridgeAddress) + const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress) + + const foreignValidatorContractAddress = await foreignBridge.methods.validatorContract().call() + const foreignValidatorContract = new web3Foreign.eth.Contract(foreignBridgeValidatorsABI, foreignValidatorContractAddress) + + const VALIDATOR_ADDRESS = privateKeyToAddress(VALIDATOR_ADDRESS_PRIVATE_KEY) + GasPrice.start('foreign') + + let nonce = await getNonce(web3Foreign, VALIDATOR_ADDRESS) + const chainId = await getChainId(web3Foreign) + + for (const message of messages) { + console.log(`Sending the tx for ${message.txHash} with nonce ${nonce}`) + try { + const job = await createRawTx({ homeBridge, foreignBridge, logger: rootLogger, colSignature: message.event, foreignValidatorContract }) + console.log({ job }) + + const gasPrice = GasPrice.getPrice() + + const gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE) + + const args = { + chain: 'foreign', + data: job.data, + nonce, + gasPrice, + amount: '0', + gasLimit: gasLimit.toString(), + privateKey: VALIDATOR_ADDRESS_PRIVATE_KEY, + to: job.to, + chainId + } + console.log({ args }) + + if (execute) { + const txHash = await sendTx({ ...args, web3: web3Foreign }).catch(error => { + console.log({ error }) + }) + console.log({ txHash }) + nonce++ + } + } catch (error) { + if (execute) { + throw error + } + } + } +} + +// call example: +// getMessages({ fromBlock: 5000000, toBlock: 5865568, isRelayedFilter: false, isNewSetFilter: false, }) + +// call example: +// relayMessages({ fromBlock: 5823914, toBlock: 5874880, execute: false, isNewSetFilter: true, limit: 1 }) + +module.exports = { + getMessages, + relayMessages +} diff --git a/native-to-erc20/oracle/src/utils/cycle.js b/native-to-erc20/oracle/src/utils/cycle.js deleted file mode 100644 index fb3864f..0000000 --- a/native-to-erc20/oracle/src/utils/cycle.js +++ /dev/null @@ -1,46 +0,0 @@ -const { getEvents } = require('../tx/web3') -const config = require('../../config/collected-signatures-watcher.config') -const { web3Home, web3Foreign } = require('../services/web3') -const { parseMessage } = require('../utils/message') - -const getMissedCycles = async () => { - -} - -const getCollectedSignatures = async ({ fromBlock, toBlock }) => { - - const homeBridge = new web3Home.eth.Contract(config.eventAbi, config.homeBridgeAddress) - const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress) - - - // config.homeBridgeAddress, - // config.foreignBridgeAddress, - const events = await getEvents({ - contract: homeBridge, - event: config.event, - fromBlock, - toBlock, - filter: config.eventFilter - }) - console.log(events.length) - for (const event of events) { - const { messageHash } = event.returnValues - const message = parseMessage(await homeBridge.methods.message(messageHash).call()) - const isRelayed = await foreignBridge.methods.relayedMessages(message.txHash).call() - console.log(isRelayed) - if (!isRelayed) { - const { blockNumber, transactionHash } = event - console.log({ blockNumber, transactionHash }) - } - } - - // const contract - return events -} - -getCollectedSignatures({ fromBlock: 4850326, toBlock: 5050326 }) - -module.exports = { - getMissedCycles, - getCollectedSignatures -} From a8ca57929c3ea65380ed989c05727fc7c05ecf80 Mon Sep 17 00:00:00 2001 From: Leon Prouger Date: Mon, 13 Jul 2020 17:04:17 +0300 Subject: [PATCH 3/9] save --- .../test/contracts/MessageWrapper.sol | 74 +++++++++++++++++++ .../processCollectedSignatures/estimateGas.js | 11 +++ native-to-erc20/oracle/src/tx/cycle.js | 6 +- 3 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 native-to-erc20/contracts/test/contracts/MessageWrapper.sol diff --git a/native-to-erc20/contracts/test/contracts/MessageWrapper.sol b/native-to-erc20/contracts/test/contracts/MessageWrapper.sol new file mode 100644 index 0000000..14f0175 --- /dev/null +++ b/native-to-erc20/contracts/test/contracts/MessageWrapper.sol @@ -0,0 +1,74 @@ +pragma solidity 0.4.24; + +contract MessageWrapper { + + function validatorRecover( + bytes _message, + uint8 _v, + bytes32 _r, + bytes32 _s + ) public returns (address recoveredAddress) { + bytes32 hash = hashMessageOfUnknownLength(_message); + recoveredAddress = ecrecover(hash, _v, _r, _s); + } + + function hashMessage(bytes message) public pure returns (bytes32) { + bytes memory prefix = "\x19Ethereum Signed Message:\n"; + // message is always 84 length + string memory msgLength = "104"; + return keccak256(abi.encodePacked(prefix, msgLength, message)); + } + + function hashMessageOfUnknownLength(bytes message) public pure returns (bytes32) { + bytes memory prefix = "\x19Ethereum Signed Message:\n"; + uint256 lengthOffset; + uint256 length; + assembly { + // The first word of a string is its length + length := mload(message) + // The beginning of the base-10 message length in the prefix + lengthOffset := add(prefix, 57) + } + uint256 lengthLength = 0; + // The divisor to get the next left-most message length digit + uint256 divisor = 100000; + // Move one digit of the message length to the right at a time + while (divisor != 0) { + // The place value at the divisor + uint256 digit = length / divisor; + if (digit == 0) { + // Skip leading zeros + if (lengthLength == 0) { + divisor /= 10; + continue; + } + } + // Found a non-zero digit or non-leading zero digit + lengthLength++; + // Remove this digit from the message length's current value + length -= digit * divisor; + // Shift our base-10 divisor over + divisor /= 10; + // Convert the digit to its ASCII representation (man ascii) + digit += 0x30; + // Move to the next character and write the digit + lengthOffset++; + assembly { + mstore8(lengthOffset, digit) + } + } + // The null string requires exactly 1 zero (unskip 1 leading 0) + if (lengthLength == 0) { + lengthLength = 1 + 0x19 + 1; + } else { + lengthLength += 1 + 0x19; + } + // Truncate the tailing zeros from the prefix + assembly { + mstore(prefix, lengthLength) + } + return keccak256(prefix, message); + } + + +} \ No newline at end of file diff --git a/native-to-erc20/oracle/src/events/processCollectedSignatures/estimateGas.js b/native-to-erc20/oracle/src/events/processCollectedSignatures/estimateGas.js index 7893990..4774879 100644 --- a/native-to-erc20/oracle/src/events/processCollectedSignatures/estimateGas.js +++ b/native-to-erc20/oracle/src/events/processCollectedSignatures/estimateGas.js @@ -24,9 +24,14 @@ async function estimateGas ({ expectedMessageLength }) { try { + debugger let gasEstimate, methodName if (message && message.length !== 2 + 2 * expectedMessageLength) { /* see ../../utils/message.js#createMessage */ logger.debug('foreignBridge.methods.executeNewSetSignatures') + console.log({ + v, r, s, message + }) + // gasEstimate = 3000000 gasEstimate = await foreignBridge.methods .executeNewSetSignatures(v, r, s, message) .estimateGas() @@ -63,6 +68,7 @@ async function estimateGas ({ } // check if all the signatures were made by validators + const validators = {} for (let i = 0; i < v.length; i++) { const address = web3.eth.accounts.recover(message, web3.utils.toHex(v[i]), r[i], s[i]) logger.debug({ address }, 'Check that signature is from a validator') @@ -71,6 +77,11 @@ async function estimateGas ({ if (!isValidator) { throw new InvalidValidatorError(`Message signed by ${address} that is not a validator`) } + if (validators[address]) { + logger.error('validator signed twice', { address }) + throw new Error('Validator signed twice') + } + validators[address] = true } logger.error(e) diff --git a/native-to-erc20/oracle/src/tx/cycle.js b/native-to-erc20/oracle/src/tx/cycle.js index 757f941..9fdc62b 100644 --- a/native-to-erc20/oracle/src/tx/cycle.js +++ b/native-to-erc20/oracle/src/tx/cycle.js @@ -92,7 +92,6 @@ const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limit, skip }) => { const messages = (await getMessages({ fromBlock, toBlock, isNewSetFilter, isRelayedFilter: false })).slice(0, limit) - console.log({ messages }) const homeBridge = new web3Home.eth.Contract(config.eventAbi, config.homeBridgeAddress) const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress) @@ -107,6 +106,7 @@ const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limi for (const message of messages) { console.log(`Sending the tx for ${message.txHash} with nonce ${nonce}`) + console.log({ message }) try { const job = await createRawTx({ homeBridge, foreignBridge, logger: rootLogger, colSignature: message.event, foreignValidatorContract }) console.log({ job }) @@ -144,10 +144,10 @@ const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limi } // call example: -// getMessages({ fromBlock: 5000000, toBlock: 5865568, isRelayedFilter: false, isNewSetFilter: false, }) +getMessages({ fromBlock: 5831273, toBlock: 5967048, isRelayedFilter: false, isNewSetFilter: true }) // call example: -// relayMessages({ fromBlock: 5823914, toBlock: 5874880, execute: false, isNewSetFilter: true, limit: 1 }) +// relayMessages({ fromBlock: 5831273, toBlock: 5967048, execute: false, isNewSetFilter: true }) module.exports = { getMessages, From 2d1220a4c0fab80216450f989ab2889ea3153912 Mon Sep 17 00:00:00 2001 From: Leon Prouger Date: Thu, 16 Jul 2020 07:37:56 +0300 Subject: [PATCH 4/9] some more work --- .../processCollectedSignatures/createRawTx.js | 45 ++++++++++++++++--- native-to-erc20/oracle/src/tx/cycle.js | 15 ++++--- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js b/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js index 05cc341..00cbd5a 100644 --- a/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js +++ b/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js @@ -1,4 +1,5 @@ const { HttpListProviderError } = require('http-list-provider') +const Web3 = require('web3') const { signatureToVRS } = require('../../utils/message') const estimateGas = require('./estimateGas') const { @@ -7,6 +8,8 @@ const { InvalidValidatorError } = require('../../utils/errors') +const web3 = new Web3() + const createRawTx = async ({ homeBridge, foreignBridge, logger, colSignature, foreignValidatorContract }) => { const { messageHash, NumberOfCollectedSignatures } = colSignature.returnValues @@ -20,16 +23,46 @@ const createRawTx = async ({ homeBridge, foreignBridge, logger, colSignature, fo const [v, r, s] = [[], [], []] logger.debug('Getting message signatures') - const signaturePromises = requiredSignatures.map(async (el, index) => { + // const signaturePromises = requiredSignatures.map(async (el, index) => { + // logger.debug({ index }, 'Getting message signature') + // const signature = await homeBridge.methods.signature(messageHash, index).call() + // const recover = signatureToVRS(signature) + // const address = web3.eth.accounts.recover(message, web3.utils.toHex(recover.v), recover.r, recover.s) + + // logger.debug({ address }, 'Check that signature is from a validator') + // const isValidator = await validatorContract.methods.isValidator(address).call() + + // if (isValidator) { + // v.push(recover.v) + // r.push(recover.r) + // s.push(recover.s) + // // throw new InvalidValidatorError(`Message signed by ${address} that is not a validator`) + // } + // }) + let index = 0 + debugger + console.log({ NumberOfCollectedSignatures }) + while (v.length < NumberOfCollectedSignatures) { logger.debug({ index }, 'Getting message signature') const signature = await homeBridge.methods.signature(messageHash, index).call() const recover = signatureToVRS(signature) - v.push(recover.v) - r.push(recover.r) - s.push(recover.s) - }) + const address = web3.eth.accounts.recover(message, web3.utils.toHex(recover.v), recover.r, recover.s) + + logger.debug({ address }, 'Check that signature is from a validator') + const isValidator = await foreignValidatorContract.methods.isValidator(address).call() + + if (isValidator) { + v.push(recover.v) + r.push(recover.r) + s.push(recover.s) + } else { + logger.debug({ address }, 'Is not validator') + } + console.log(v.length) + index++ + } - await Promise.all(signaturePromises) + // await Promise.all(signaturePromises) let gasEstimate, methodName try { diff --git a/native-to-erc20/oracle/src/tx/cycle.js b/native-to-erc20/oracle/src/tx/cycle.js index 9fdc62b..65066e2 100644 --- a/native-to-erc20/oracle/src/tx/cycle.js +++ b/native-to-erc20/oracle/src/tx/cycle.js @@ -30,20 +30,24 @@ const parseGenericMessage = (unparsedMessage, expectedMessageLength) => { } } -const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter }) => { +const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter, event }) => { console.log({ fromBlock, toBlock, isRelayedFilter }) const homeBridge = new web3Home.eth.Contract(config.eventAbi, config.homeBridgeAddress) const expectedMessageLength = await homeBridge.methods.requiredMessageLength().call() - + // console.log(config.eventFilter) const events = await getEvents({ contract: homeBridge, - event: config.event, + event: event || config.event, fromBlock, toBlock, filter: config.eventFilter }) + if (event === 'SignedForUserRequest') { + events.forEach(event => console.log(event.returnValues.signer)) + return + } let messages = [] for (const event of events) { const { messageHash } = event.returnValues @@ -108,6 +112,7 @@ const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limi console.log(`Sending the tx for ${message.txHash} with nonce ${nonce}`) console.log({ message }) try { + debugger const job = await createRawTx({ homeBridge, foreignBridge, logger: rootLogger, colSignature: message.event, foreignValidatorContract }) console.log({ job }) @@ -144,10 +149,10 @@ const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limi } // call example: -getMessages({ fromBlock: 5831273, toBlock: 5967048, isRelayedFilter: false, isNewSetFilter: true }) +getMessages({ fromBlock: 5831273, toBlock: 5831287, isRelayedFilter: false, isNewSetFilter: false, event: 'SignedForUserRequest' }) // call example: -// relayMessages({ fromBlock: 5831273, toBlock: 5967048, execute: false, isNewSetFilter: true }) +// relayMessages({ fromBlock: 5999394, toBlock: 6000000, execute: false, isNewSetFilter: false }) module.exports = { getMessages, From 747621f7c3805076a3ab3f178dafb0c321c7e620 Mon Sep 17 00:00:00 2001 From: Leon Prouger Date: Thu, 16 Jul 2020 15:42:11 +0300 Subject: [PATCH 5/9] adding initiateChange --- .../src/events/processInitiateChange/index.js | 2 +- native-to-erc20/oracle/src/tx/cycle.js | 40 ++++++++++++++++--- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/native-to-erc20/oracle/src/events/processInitiateChange/index.js b/native-to-erc20/oracle/src/events/processInitiateChange/index.js index 3da025a..d5563af 100644 --- a/native-to-erc20/oracle/src/events/processInitiateChange/index.js +++ b/native-to-erc20/oracle/src/events/processInitiateChange/index.js @@ -72,7 +72,7 @@ function processInitiateChangeBuilder (config) { const foreignBridgeVersion = await foreignBridgeStorage.methods.version().call() const message = createNewSetMessage({ foreignBridgeVersion, - newSet: newSet, + newSet: [...newSet], transactionHash: initiateChange.transactionHash, blockNumber, bridgeAddress: foreignBridgeAddress diff --git a/native-to-erc20/oracle/src/tx/cycle.js b/native-to-erc20/oracle/src/tx/cycle.js index 65066e2..b27a8f5 100644 --- a/native-to-erc20/oracle/src/tx/cycle.js +++ b/native-to-erc20/oracle/src/tx/cycle.js @@ -1,5 +1,4 @@ const { getEvents } = require('./web3') -const config = require('../../config/collected-signatures-watcher.config') const { web3Home, web3Foreign } = require('../services/web3') const { sendTx } = require('./sendTx') const { parseMessage, parseNewSetMessage } = require('../utils/message') @@ -12,6 +11,7 @@ const { } = require('../utils/utils') const { EXTRA_GAS_PERCENTAGE } = require('../utils/constants') +const processInitiateChangeBuilder = require('../events/processInitiateChange') const foreignBridgeValidatorsABI = require('../../abis/ForeignBridgeValidators.abi') const rootLogger = require('../services/logger') @@ -31,6 +31,8 @@ const parseGenericMessage = (unparsedMessage, expectedMessageLength) => { } const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter, event }) => { + const config = require('../../config/collected-signatures-watcher.config') + console.log({ fromBlock, toBlock, isRelayedFilter }) const homeBridge = new web3Home.eth.Contract(config.eventAbi, config.homeBridgeAddress) @@ -44,10 +46,11 @@ const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter filter: config.eventFilter }) - if (event === 'SignedForUserRequest') { - events.forEach(event => console.log(event.returnValues.signer)) - return + if (event === 'SignedForUserRequest' || event === 'InitiateChange') { + // events.forEach(event => console.log(event.returnValues.signer)) + return events } + let messages = [] for (const event of events) { const { messageHash } = event.returnValues @@ -95,6 +98,8 @@ const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter } const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limit, skip }) => { + const config = require('../../config/collected-signatures-watcher.config') + const messages = (await getMessages({ fromBlock, toBlock, isNewSetFilter, isRelayedFilter: false })).slice(0, limit) const homeBridge = new web3Home.eth.Contract(config.eventAbi, config.homeBridgeAddress) const foreignBridge = new web3Foreign.eth.Contract(config.foreignBridgeAbi, config.foreignBridgeAddress) @@ -148,12 +153,37 @@ const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limi } } +const sendInitiateChange = async ({ fromBlock, toBlock }) => { + const config = require('../../config/initiate-change-watcher.config') + const eventContract = new web3Home.eth.Contract(config.eventAbi, '0x3014ca10b91cb3D0AD85fEf7A3Cb95BCAc9c0f79') + debugger + const events = await getEvents({ + contract: eventContract, + event: config.event, + fromBlock, + toBlock, + filter: config.eventFilter + }) + // const events = await getMessages({ fromBlock, toBlock, event: 'InitiateChange' }) + console.log({ events }) + + const processInitiateChange = processInitiateChangeBuilder(config) + + await processInitiateChange( + [events[0]], + config.homeBridgeAddress, + config.foreignBridgeAddress + ) +} + // call example: -getMessages({ fromBlock: 5831273, toBlock: 5831287, isRelayedFilter: false, isNewSetFilter: false, event: 'SignedForUserRequest' }) +// getMessages({ fromBlock: 5831273, toBlock: 5831287, isRelayedFilter: false, isNewSetFilter: false, event: 'SignedForUserRequest' }) // call example: // relayMessages({ fromBlock: 5999394, toBlock: 6000000, execute: false, isNewSetFilter: false }) +sendInitiateChange({ fromBlock: 5831273, toBlock: 6000000, execute: false }) + module.exports = { getMessages, relayMessages From f9f42abd9e4142de56d7ae87a13574e08065abac Mon Sep 17 00:00:00 2001 From: Leon Prouger Date: Thu, 16 Jul 2020 20:23:02 +0300 Subject: [PATCH 6/9] fixes --- native-to-erc20/oracle/src/tx/cycle.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/native-to-erc20/oracle/src/tx/cycle.js b/native-to-erc20/oracle/src/tx/cycle.js index b27a8f5..c731edb 100644 --- a/native-to-erc20/oracle/src/tx/cycle.js +++ b/native-to-erc20/oracle/src/tx/cycle.js @@ -47,7 +47,7 @@ const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter }) if (event === 'SignedForUserRequest' || event === 'InitiateChange') { - // events.forEach(event => console.log(event.returnValues.signer)) + events.forEach(event => console.log(event.returnValues.signer)) return events } @@ -177,14 +177,15 @@ const sendInitiateChange = async ({ fromBlock, toBlock }) => { } // call example: -// getMessages({ fromBlock: 5831273, toBlock: 5831287, isRelayedFilter: false, isNewSetFilter: false, event: 'SignedForUserRequest' }) +getMessages({ fromBlock: 6000000, toBlock: 6022014, isRelayedFilter: false, isNewSetFilter: false, event: 'SignedForUserRequest' }) // call example: // relayMessages({ fromBlock: 5999394, toBlock: 6000000, execute: false, isNewSetFilter: false }) -sendInitiateChange({ fromBlock: 5831273, toBlock: 6000000, execute: false }) +// sendInitiateChange({ fromBlock: 5831273, toBlock: 6000000, execute: false }) module.exports = { getMessages, - relayMessages + relayMessages, + sendInitiateChange } From a8e2d51b50d60a4a6d9f65f8f5e1af575e54965e Mon Sep 17 00:00:00 2001 From: Leon Prouger Date: Fri, 17 Jul 2020 20:47:16 +0300 Subject: [PATCH 7/9] work --- .../processCollectedSignatures/createRawTx.js | 45 ++++--------------- native-to-erc20/oracle/src/tx/cycle.js | 31 ++++++++----- 2 files changed, 29 insertions(+), 47 deletions(-) diff --git a/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js b/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js index 00cbd5a..718a3ac 100644 --- a/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js +++ b/native-to-erc20/oracle/src/events/processCollectedSignatures/createRawTx.js @@ -23,46 +23,19 @@ const createRawTx = async ({ homeBridge, foreignBridge, logger, colSignature, fo const [v, r, s] = [[], [], []] logger.debug('Getting message signatures') - // const signaturePromises = requiredSignatures.map(async (el, index) => { - // logger.debug({ index }, 'Getting message signature') - // const signature = await homeBridge.methods.signature(messageHash, index).call() - // const recover = signatureToVRS(signature) - // const address = web3.eth.accounts.recover(message, web3.utils.toHex(recover.v), recover.r, recover.s) - - // logger.debug({ address }, 'Check that signature is from a validator') - // const isValidator = await validatorContract.methods.isValidator(address).call() - - // if (isValidator) { - // v.push(recover.v) - // r.push(recover.r) - // s.push(recover.s) - // // throw new InvalidValidatorError(`Message signed by ${address} that is not a validator`) - // } - // }) - let index = 0 - debugger - console.log({ NumberOfCollectedSignatures }) - while (v.length < NumberOfCollectedSignatures) { + const signaturePromises = requiredSignatures.map(async (el, index) => { logger.debug({ index }, 'Getting message signature') const signature = await homeBridge.methods.signature(messageHash, index).call() const recover = signatureToVRS(signature) - const address = web3.eth.accounts.recover(message, web3.utils.toHex(recover.v), recover.r, recover.s) - - logger.debug({ address }, 'Check that signature is from a validator') - const isValidator = await foreignValidatorContract.methods.isValidator(address).call() - - if (isValidator) { - v.push(recover.v) - r.push(recover.r) - s.push(recover.s) - } else { - logger.debug({ address }, 'Is not validator') - } - console.log(v.length) - index++ - } + v.push(recover.v) + r.push(recover.r) + s.push(recover.s) + }) + // let index = 0 + // debugger + // console.log({ NumberOfCollectedSignatures }) - // await Promise.all(signaturePromises) + await Promise.all(signaturePromises) let gasEstimate, methodName try { diff --git a/native-to-erc20/oracle/src/tx/cycle.js b/native-to-erc20/oracle/src/tx/cycle.js index c731edb..9f0db26 100644 --- a/native-to-erc20/oracle/src/tx/cycle.js +++ b/native-to-erc20/oracle/src/tx/cycle.js @@ -32,6 +32,7 @@ const parseGenericMessage = (unparsedMessage, expectedMessageLength) => { const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter, event }) => { const config = require('../../config/collected-signatures-watcher.config') + toBlock = toBlock || await web3Home.eth.getBlockNumber() console.log({ fromBlock, toBlock, isRelayedFilter }) const homeBridge = new web3Home.eth.Contract(config.eventAbi, config.homeBridgeAddress) @@ -46,8 +47,10 @@ const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter filter: config.eventFilter }) + console.log({ events }) + if (event === 'SignedForUserRequest' || event === 'InitiateChange') { - events.forEach(event => console.log(event.returnValues.signer)) + events.forEach(event => console.log(event.returnValues)) return events } @@ -153,7 +156,10 @@ const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limi } } -const sendInitiateChange = async ({ fromBlock, toBlock }) => { +const sendInitiateChange = async ({ fromBlock, toBlock, execute }) => { + toBlock = toBlock || await web3Home.eth.getBlockNumber() + console.log({ fromBlock, toBlock }) + const config = require('../../config/initiate-change-watcher.config') const eventContract = new web3Home.eth.Contract(config.eventAbi, '0x3014ca10b91cb3D0AD85fEf7A3Cb95BCAc9c0f79') debugger @@ -165,22 +171,25 @@ const sendInitiateChange = async ({ fromBlock, toBlock }) => { filter: config.eventFilter }) // const events = await getMessages({ fromBlock, toBlock, event: 'InitiateChange' }) - console.log({ events }) + // console.log({ events }) + console.log(events.length) - const processInitiateChange = processInitiateChangeBuilder(config) + if (execute) { + const processInitiateChange = processInitiateChangeBuilder(config) - await processInitiateChange( - [events[0]], - config.homeBridgeAddress, - config.foreignBridgeAddress - ) + await processInitiateChange( + [events[0]], + config.homeBridgeAddress, + config.foreignBridgeAddress + ) + } } // call example: -getMessages({ fromBlock: 6000000, toBlock: 6022014, isRelayedFilter: false, isNewSetFilter: false, event: 'SignedForUserRequest' }) +getMessages({ fromBlock: 5999398, isRelayedFilter: false, isNewSetFilter: true }) // call example: -// relayMessages({ fromBlock: 5999394, toBlock: 6000000, execute: false, isNewSetFilter: false }) +// relayMessages({ fromBlock: 5999398, toBlock: 5999399, isRelayedFilter: false, isNewSetFilter: false, execute: true }) // sendInitiateChange({ fromBlock: 5831273, toBlock: 6000000, execute: false }) From 75e1f3d21d0ac661808da883438dca832a992053 Mon Sep 17 00:00:00 2001 From: Leon Prouger Date: Sun, 9 Aug 2020 10:41:59 +0300 Subject: [PATCH 8/9] saving --- native-to-erc20/oracle/src/tx/cycle.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/native-to-erc20/oracle/src/tx/cycle.js b/native-to-erc20/oracle/src/tx/cycle.js index 9f0db26..ef49f86 100644 --- a/native-to-erc20/oracle/src/tx/cycle.js +++ b/native-to-erc20/oracle/src/tx/cycle.js @@ -186,10 +186,10 @@ const sendInitiateChange = async ({ fromBlock, toBlock, execute }) => { } // call example: -getMessages({ fromBlock: 5999398, isRelayedFilter: false, isNewSetFilter: true }) +// getMessages({ fromBlock: 5969512, isRelayedFilter: false, isNewSetFilter: true }) // call example: -// relayMessages({ fromBlock: 5999398, toBlock: 5999399, isRelayedFilter: false, isNewSetFilter: false, execute: true }) +relayMessages({ fromBlock: 6211433, toBlock: 6224313, isRelayedFilter: false, isNewSetFilter: true, execute: true }) // sendInitiateChange({ fromBlock: 5831273, toBlock: 6000000, execute: false }) From 02000d5cc69a052fcb54bd0aa6b402a2c11c7e64 Mon Sep 17 00:00:00 2001 From: Leon Prouger Date: Sat, 26 Sep 2020 19:56:18 +0300 Subject: [PATCH 9/9] addig docs --- native-to-erc20/oracle/src/tx/cycle.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/native-to-erc20/oracle/src/tx/cycle.js b/native-to-erc20/oracle/src/tx/cycle.js index ef49f86..b82ffb2 100644 --- a/native-to-erc20/oracle/src/tx/cycle.js +++ b/native-to-erc20/oracle/src/tx/cycle.js @@ -30,6 +30,16 @@ const parseGenericMessage = (unparsedMessage, expectedMessageLength) => { } } +/** + * Fetch the messages from Fuse network that intended to be relayed to Ethereum. + * The messages can represent updates to the validators set, minting on EoC, or bridge transfers + * @param {number} fromBlock - from blocknumber to look for messages + * @param {number} toBlock - to blocknumber block to look messages + * @param {bool} isRelayedFilter - if false will filter already relayed messages + * @param {bool} isNewSetFilter - if true will filter only new validator set updates + * @param {string} event - if specifed fetch other events like SignedForUserRequest or InitiateChange + */ + const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter, event }) => { const config = require('../../config/collected-signatures-watcher.config') toBlock = toBlock || await web3Home.eth.getBlockNumber() @@ -100,7 +110,16 @@ const getMessages = async ({ fromBlock, toBlock, isRelayedFilter, isNewSetFilter return filteredMessages } -const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limit, skip }) => { +/** + * Relay the messages from Fuse network to Ethereum. + * The messages can represent updates to the validators set, minting on EoC, or bridge transfers + * @param {number} fromBlock - from blocknumber to look for messages + * @param {number} toBlock - to blocknumber block to look messages + * @param {bool} execute - on true will try to to send tx on Ethereum, otherwise acts like a dry run + * @param {bool} isNewSetFilter - if true will filter only new validator set updates + * @param {number} limit - limit number of relayed messages. It's advice to set to 1 when executing. + */ +const relayMessages = async ({ fromBlock, toBlock, execute, isNewSetFilter, limit }) => { const config = require('../../config/collected-signatures-watcher.config') const messages = (await getMessages({ fromBlock, toBlock, isNewSetFilter, isRelayedFilter: false })).slice(0, limit) @@ -189,7 +208,7 @@ const sendInitiateChange = async ({ fromBlock, toBlock, execute }) => { // getMessages({ fromBlock: 5969512, isRelayedFilter: false, isNewSetFilter: true }) // call example: -relayMessages({ fromBlock: 6211433, toBlock: 6224313, isRelayedFilter: false, isNewSetFilter: true, execute: true }) +relayMessages({ fromBlock: 5969512, toBlock: 7213700, isRelayedFilter: false, isNewSetFilter: false, execute: false }) // sendInitiateChange({ fromBlock: 5831273, toBlock: 6000000, execute: false })