Files
Validation-Ledger-Tx-Store-…/lib/onTransaction.mjs
2023-11-22 16:47:32 +01:00

135 lines
4.6 KiB
JavaScript

import { writeFile } from 'fs'
import { dirExists } from './dirExists.mjs'
import { ledgerIndexToFolders } from './ledgerIndexToFolders.mjs'
import { xpopGenerate } from './xpopGenerate.mjs'
import { createDirectory } from './createDirectory.mjs'
import { waitForLedgerReady } from './events/ledgerReady.mjs'
import { emit } from '../bin/webserver.mjs'
import 'dotenv/config'
let txCount = 0
const xpopBinaryDir = new URL('../store/xpop', import.meta.url).pathname
const lastSeenTransactions = []
const fields = (process.env?.FIELDSREQUIRED || '')
.split(',')
.map(f => f.trim())
.filter(f => f.match(/^[a-zA-Z0-9]+$/))
const fieldsRequired = fields.length === 1 && fields[0] === ''
? [ 'Fee' ]
: fields
const hasRequiredFields = tx => fieldsRequired.map(f => Object.keys(tx).includes(f)).every(f => !!f)
const onTransaction = async ({
networkId,
transaction,
}) => {
if (transaction?.validated) {
const { transaction: tx } = transaction
if (tx.hash && lastSeenTransactions.indexOf(tx.hash) < 0) {
lastSeenTransactions.unshift(tx.hash)
lastSeenTransactions.length = 3000
const validTx = hasRequiredFields(tx)
if (!process.env?.NOELIGIBLEFULLTXLOG) {
console.log('TX', tx.hash, validTx)
}
if (validTx && transaction?.ledger_index) {
const relativeStorDir = 'store/' + networkId + '/' + ledgerIndexToFolders(transaction.ledger_index)
const storeDir = new URL('../' + relativeStorDir, import.meta.url).pathname
console.log('xPOP eligible', relativeStorDir, process.env?.NOELIGIBLEFULLTXLOG ? tx.hash : tx)
if (await dirExists(storeDir)) {
const wroteTxFile = await new Promise(resolve => {
writeFile(storeDir + '/tx_' + tx.hash + '.json', Buffer.from(JSON.stringify(transaction), 'utf8'), err => {
if (err) {
console.log('Error writing file @ ' + storeDir)
resolve(false)
}
resolve(true)
})
})
if (wroteTxFile) {
await waitForLedgerReady(transaction.ledger_index)
// Make sure IO & validation messages get some time to be processed
await new Promise(resolve => setTimeout(resolve, 2_000))
/**
* TX all ready, written to filesystem, ...
* This is where we start a slight delay to give the `onLedger`
* routine some time to fetch & store and then we'll try to
* generate an xPOP.
*/
const xpopBinary = await xpopGenerate({
ledgerIndex: transaction.ledger_index,
networkId,
txHash: tx.hash,
})
if (!(await dirExists(xpopBinaryDir))) {
console.log('(Re-) creating /store/xpop directory')
await createDirectory('store/xpop')
}
const xpopWritten = await new Promise(resolve => {
writeFile(xpopBinaryDir + '/' + tx.hash, Buffer.from(xpopBinary, 'utf8'), err => {
if (err) {
console.log('Error writing binary XPOP', err)
resolve(false)
} else {
console.log('Wrote binary xPOP: ' + xpopBinaryDir + '/' + tx.hash)
resolve(true)
}
})
})
if (xpopWritten) {
console.log(' ### EMIT XPOP READY FOR', tx?.Account, Number(tx.Sequence), tx.hash)
txCount++
return await emit({
account: tx?.Account,
sequence: tx.Sequence,
origin: {
tx: tx.hash,
networkId: networkId,
ledgerIndex: transaction.ledger_index,
burn: tx?.Fee,
},
destination: {
networkId: tx?.OperationLimit,
},
...(
process.env?.URL_PREFIX
? {
xpop: {
binary: `${process.env.URL_PREFIX}/xpop/${tx.hash}`,
source: `${process.env.URL_PREFIX}/${networkId}/${ledgerIndexToFolders(transaction.ledger_index)}/`,
blob: xpopBinary,
}
}
: {}
)
})
}
}
}
}
}
}
}
export {
onTransaction,
txCount,
}