fix bugs for account root update

This commit is contained in:
Alexey 2020-11-25 22:42:16 +01:00
parent e8bf718143
commit 008433adb4
3 changed files with 22 additions and 53 deletions

@ -29,7 +29,7 @@
"node-fetch": "^2.6.0", "node-fetch": "^2.6.0",
"torn-token": "git+ssh://git@github.com/tornadocash/torn-token.git#04c4df88d470ca7503ef5d97882c56cba4f3647d", "torn-token": "git+ssh://git@github.com/tornadocash/torn-token.git#04c4df88d470ca7503ef5d97882c56cba4f3647d",
"tornado-cash-anonymity-mining": "git+ssh://git@github.com/tornadocash/tornado-anonymity-mining.git#b13228c20126f212ebbcc5a8493ce2105210739e", "tornado-cash-anonymity-mining": "git+ssh://git@github.com/tornadocash/tornado-anonymity-mining.git#b13228c20126f212ebbcc5a8493ce2105210739e",
"tx-manager": "^0.2.6", "tx-manager": "^0.2.8",
"uuid": "^8.3.0", "uuid": "^8.3.0",
"web3": "^1.3.0", "web3": "^1.3.0",
"web3-core-promievent": "^1.3.0", "web3-core-promievent": "^1.3.0",

@ -48,6 +48,7 @@ const status = Object.freeze({
MINED: 'MINED', MINED: 'MINED',
CONFIRMED: 'CONFIRMED', CONFIRMED: 'CONFIRMED',
FAILED: 'FAILED', FAILED: 'FAILED',
RESUBMITTED: 'RESUBMITTED',
}) })
async function fetchTree() { async function fetchTree() {
@ -83,7 +84,11 @@ async function fetchTree() {
async function start() { async function start() {
web3 = new Web3(httpRpcUrl) web3 = new Web3(httpRpcUrl)
const { CONFIRMATIONS, MAX_GAS_PRICE } = process.env const { CONFIRMATIONS, MAX_GAS_PRICE } = process.env
txManager = new TxManager({ privateKey, rpcUrl: httpRpcUrl, config: { CONFIRMATIONS, MAX_GAS_PRICE } }) txManager = new TxManager({
privateKey,
rpcUrl: httpRpcUrl,
config: { CONFIRMATIONS, MAX_GAS_PRICE, THROW_ON_REVERT: false },
})
swap = new web3.eth.Contract(swapABI, await resolver.resolve(torn.rewardSwap.address)) swap = new web3.eth.Contract(swapABI, await resolver.resolve(torn.rewardSwap.address))
minerContract = new web3.eth.Contract(miningABI, await resolver.resolve(torn.miningV2.address)) minerContract = new web3.eth.Contract(miningABI, await resolver.resolve(torn.miningV2.address))
proxyContract = new web3.eth.Contract(tornadoProxyABI, await resolver.resolve(torn.tornadoProxy.address)) proxyContract = new web3.eth.Contract(tornadoProxyABI, await resolver.resolve(torn.tornadoProxy.address))
@ -175,7 +180,7 @@ async function checkMiningFee({ args }) {
} }
} }
async function getTxObject({ data }) { function getTxObject({ data }) {
if (data.type === jobType.TORNADO_WITHDRAW) { if (data.type === jobType.TORNADO_WITHDRAW) {
let contract, calldata let contract, calldata
if (getInstance(data.contract).currency === 'eth') { if (getInstance(data.contract).currency === 'eth') {
@ -200,53 +205,17 @@ async function getTxObject({ data }) {
} }
} }
function extractRevertReason(msg) {
console.log('RAW error message:', msg)
if (!msg.startsWith('Node error: ')) {
console.log('Failed to parse error message from Ethereum call: ' + msg)
return null
}
// Trim "Node error: "
const errorObjectStr = msg.slice(12)
// Parse the error object
const errorObject = JSON.parse(errorObjectStr)
if (!errorObject.data) {
console.log('Failed to parse data field error object:' + errorObjectStr)
return null
}
if (errorObject.data.startsWith('Reverted 0x')) {
// Trim "Reverted 0x" from the data field
msg = errorObject.data.slice(11)
} else if (errorObject.data.startsWith('0x')) {
// Trim "0x" from the data field
msg = errorObject.data.slice(2)
} else {
console.log('Failed to parse data field error object:' + errorObjectStr)
return null
}
// Get the length of the revert reason
const strLen = parseInt(msg.slice(8 + 64, 8 + 128), 16)
// Using the length and known offset, extract and convert the revert reason
const reasonCodeHex = msg.slice(8 + 128, 8 + 128 + (strLen * 2))
// Convert reason from hex to string
const reason = web3.utils.hexToAscii('0x' + reasonCodeHex)
return reason
}
async function isOutdatedTreeRevert(receipt, currentTx) { async function isOutdatedTreeRevert(receipt, currentTx) {
try { try {
await web3.eth.call(currentTx.tx, receipt.blockNumber) await web3.eth.call(currentTx.tx, receipt.blockNumber)
console.log('Simulated call successful') console.log('Simulated call successful')
return false return false
} catch(e) { } catch (e) {
const reason = extractRevertReason(e.message) console.log('Decoded revert reason:', e.message)
console.log('Decoded revert reason:', reason) return (
return reason === 'Outdated account merkle root' || reason === 'Outdated tree update merkle root' e.message.indexOf('Outdated account merkle root') !== -1 ||
e.message.indexOf('Outdated tree update merkle root') !== -1
)
} }
} }
@ -260,7 +229,7 @@ async function processJob(job) {
console.log(`Start processing a new ${job.data.type} job #${job.id}`) console.log(`Start processing a new ${job.data.type} job #${job.id}`)
await submitTx(job) await submitTx(job)
} catch (e) { } catch (e) {
console.error(e) console.error('processJob', e.message)
await updateStatus(status.FAILED) await updateStatus(status.FAILED)
throw e throw e
} }
@ -268,7 +237,7 @@ async function processJob(job) {
async function submitTx(job, retry = 0) { async function submitTx(job, retry = 0) {
await checkFee(job) await checkFee(job)
currentTx = await txManager.createTx(await getTxObject(job)) currentTx = await txManager.createTx(getTxObject(job))
if (job.data.type !== jobType.TORNADO_WITHDRAW) { if (job.data.type !== jobType.TORNADO_WITHDRAW) {
await fetchTree() await fetchTree()
@ -290,8 +259,9 @@ async function submitTx(job, retry = 0) {
if (receipt.status === 1) { if (receipt.status === 1) {
await updateStatus(status.CONFIRMED) await updateStatus(status.CONFIRMED)
} else { } else {
if (job.data.type !== jobType.TORNADO_WITHDRAW && await isOutdatedTreeRevert(receipt, currentTx)) { if (job.data.type !== jobType.TORNADO_WITHDRAW && (await isOutdatedTreeRevert(receipt, currentTx))) {
if (retry < 3) { if (retry < 3) {
await updateStatus(status.RESUBMITTED)
await submitTx(job, retry + 1) await submitTx(job, retry + 1)
} else { } else {
throw new Error('Tree update retry limit exceeded') throw new Error('Tree update retry limit exceeded')
@ -303,7 +273,6 @@ async function submitTx(job, retry = 0) {
} catch (e) { } catch (e) {
// todo this could result in duplicated error logs // todo this could result in duplicated error logs
// todo handle a case where account tree is still not up to date (wait and retry)? // todo handle a case where account tree is still not up to date (wait and retry)?
console.error('Revert', e)
throw new Error(`Revert by smart contract ${e.message}`) throw new Error(`Revert by smart contract ${e.message}`)
} }
} }

@ -4384,10 +4384,10 @@ tweetnacl@^1.0.0:
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
tx-manager@^0.2.6: tx-manager@^0.2.8:
version "0.2.6" version "0.2.8"
resolved "https://registry.yarnpkg.com/tx-manager/-/tx-manager-0.2.6.tgz#05f49794695ebd71c58b794bb213927efdbf6d3e" resolved "https://registry.yarnpkg.com/tx-manager/-/tx-manager-0.2.8.tgz#9175782f16c1fc3de9d5bcdec8c408e8474bf45a"
integrity sha512-19h+PacgoUuXbN2wKTpb4R+MxD9fOxil3ZsvnDRG/Z4pPboUzd/D2+VBdcH9+EEVGXovZ6bcVggIZ4RIO7LO1w== integrity sha512-Uo3Jz9NfCZucwwVXuB6MYImIX6Yq8YRhRAJbMMGQMbwG+ghs4mG8p6+GNld7ZA2sH7qdEzY5c3Sk+BROznIAGw==
dependencies: dependencies:
async-mutex "^0.2.4" async-mutex "^0.2.4"
ethers "^5.0.17" ethers "^5.0.17"