mirror of
				https://github.com/Xahau/Validation-Ledger-Tx-Store-to-xPOP.git
				synced 2025-11-04 12:25:48 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			156 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import { writeFile } from 'fs'
 | 
						|
import { ledgerIndexToFolders } from './ledgerIndexToFolders.mjs'
 | 
						|
import { computeBinaryTransactionHash } from './computeBinaryTransactionHash.mjs'
 | 
						|
import { dirExists } from './dirExists.mjs'
 | 
						|
import { ledgerReady, waitForLedgerReady } from './events/ledgerReady.mjs'
 | 
						|
import { onTransaction } from './onTransaction.mjs'
 | 
						|
import 'dotenv/config'
 | 
						|
 | 
						|
const obtainedHumanReadableLedgers = []
 | 
						|
const obtainedBinaryTxLedgers = []
 | 
						|
 | 
						|
let lastLedger
 | 
						|
 | 
						|
const onLedger = async ({
 | 
						|
  networkId,
 | 
						|
  ledger,
 | 
						|
  connection,
 | 
						|
}) => {
 | 
						|
  if ((ledger?.type || '').toUpperCase() === 'LEDGERCLOSED') {
 | 
						|
    if (ledger?.txn_count > 0 && ledger?.ledger_index) {
 | 
						|
      const relativeStoreDir = 'store/' + networkId + '/' + ledgerIndexToFolders(ledger.ledger_index)
 | 
						|
      const storeDir = new URL('../' + relativeStoreDir, import.meta.url).pathname
 | 
						|
 | 
						|
      lastLedger = ledger.ledger_index
 | 
						|
 | 
						|
      if (await dirExists(storeDir)) {
 | 
						|
        const ledgerData = [
 | 
						|
          ...(
 | 
						|
            obtainedBinaryTxLedgers.indexOf(ledger.ledger_index) < 0
 | 
						|
              ? [
 | 
						|
                  connection.send({
 | 
						|
                    command: 'ledger',
 | 
						|
                    ledger_index: ledger.ledger_index,
 | 
						|
                    transactions: true,
 | 
						|
                    expand: true,
 | 
						|
                    binary: true,
 | 
						|
                  })
 | 
						|
                ]
 | 
						|
              : []),
 | 
						|
          ...(
 | 
						|
            obtainedHumanReadableLedgers.indexOf(ledger.ledger_index) < 0
 | 
						|
              ? [
 | 
						|
                  connection.send({
 | 
						|
                    command: 'ledger',
 | 
						|
                    ledger_index: ledger.ledger_index,
 | 
						|
                    transactions: true,
 | 
						|
                    expand: true,
 | 
						|
                    binary: false,
 | 
						|
                  })
 | 
						|
                ]
 | 
						|
              : []),
 | 
						|
        ].map(query => query.then(results => {
 | 
						|
          if (results?.validated && results?.ledger_index === ledger?.ledger_index && results?.ledger_hash === ledger?.ledger_hash) {
 | 
						|
            if (
 | 
						|
              results?.ledger?.transactions
 | 
						|
              && Array.isArray(results.ledger.transactions)
 | 
						|
              && results.ledger.transactions.length > 0
 | 
						|
              && obtainedBinaryTxLedgers.indexOf(ledger.ledger_index) < 0
 | 
						|
            ) {
 | 
						|
              /**
 | 
						|
               * Store in array, so if more ledger events come in and they
 | 
						|
               * also result in a response here, it won't be saved again.
 | 
						|
               * So yes: events will come in multiple times if multiple
 | 
						|
               * nodes are connected, and yes, multiple promises will be
 | 
						|
               * fired to fetch the ledger information, but then only
 | 
						|
               * the first one will be stored.
 | 
						|
               */
 | 
						|
              obtainedBinaryTxLedgers.unshift(results.ledger_index)
 | 
						|
              obtainedBinaryTxLedgers.length = 250
 | 
						|
 | 
						|
              console.log('Obtained ledger (binary)', relativeStoreDir, results.ledger_index, 'TX#', results.ledger.transactions.length)
 | 
						|
 | 
						|
              /**
 | 
						|
               * Merge transaction hashes with the raw tx data
 | 
						|
               */
 | 
						|
              ;(results?.ledger?.transactions || []).map(t => {
 | 
						|
                return Object.assign(t, { tx_id: computeBinaryTransactionHash(t.tx_blob), })
 | 
						|
              })
 | 
						|
 | 
						|
              writeFile(storeDir + '/ledger_binary_transactions.json', Buffer.from(JSON.stringify(results.ledger), 'utf8'), err => {
 | 
						|
                if (err) {
 | 
						|
                  console.log('Error writing file @ ' + storeDir)
 | 
						|
                } else {
 | 
						|
                  ledgerReady(results.ledger_index, 'ledger_binary_transactions')
 | 
						|
                }
 | 
						|
              })
 | 
						|
            }
 | 
						|
            if (
 | 
						|
              results?.ledger?.parent_hash
 | 
						|
              && obtainedHumanReadableLedgers.indexOf(ledger.ledger_index) < 0
 | 
						|
              && results?.ledger?.ledger_hash === ledger?.ledger_hash
 | 
						|
            ) {
 | 
						|
              /**
 | 
						|
               * See comment above "Store in array" ... - first one will be stored
 | 
						|
               */
 | 
						|
              obtainedHumanReadableLedgers.unshift(results.ledger_index)
 | 
						|
              obtainedHumanReadableLedgers.length = 250
 | 
						|
        
 | 
						|
              console.log('Obtained ledger (JSON object)', relativeStoreDir, results.ledger_index, 'Hash', results.ledger.ledger_hash)
 | 
						|
 | 
						|
              writeFile(storeDir + '/ledger_info.json', Buffer.from(JSON.stringify({ ...results.ledger, transactions: undefined, }), 'utf8'), err => {
 | 
						|
                if (err) {
 | 
						|
                  console.log('Error writing file @ ' + storeDir)
 | 
						|
                } else {
 | 
						|
                  ledgerReady(ledger.ledger_index, 'ledger_info')
 | 
						|
                }
 | 
						|
              })
 | 
						|
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          return results.ledger
 | 
						|
        }))
 | 
						|
 | 
						|
        /**
 | 
						|
         * Deal with transactions & fire events
 | 
						|
         */
 | 
						|
        waitForLedgerReady(ledger.ledger_index)?.then(async () => {
 | 
						|
          if (ledgerData.length > 0) {
 | 
						|
            const [binary, json] = await Promise.all(ledgerData)
 | 
						|
            const sequetiallyMappedLedgerTxEvents = (json?.transactions || []).map(tx => {
 | 
						|
              return {
 | 
						|
                validated: true,
 | 
						|
                ledger_index: ledger.ledger_index,
 | 
						|
                transaction: tx,
 | 
						|
              }              
 | 
						|
            })
 | 
						|
            .sort((a, b) => a.transaction.Sequence - b.transaction.Sequence)
 | 
						|
            .reduce((promiseChain, current) => {
 | 
						|
              return promiseChain.then(() => {
 | 
						|
                // console.log('    » Tx events: Processing', current.transaction.Sequence)
 | 
						|
                return onTransaction({
 | 
						|
                  networkId,
 | 
						|
                  transaction: current,
 | 
						|
                  connection,
 | 
						|
                })
 | 
						|
              }).then(() => {
 | 
						|
                // console.log('    » Tx events: Done      ', current.transaction.Sequence)
 | 
						|
              })
 | 
						|
            }, Promise.resolve())
 | 
						|
           
 | 
						|
            sequetiallyMappedLedgerTxEvents.then(() => {
 | 
						|
              // console.log('    « « « « All transactions in ledger processed', ledger.ledger_index)
 | 
						|
            });
 | 
						|
          }
 | 
						|
        })
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export {
 | 
						|
  onLedger,
 | 
						|
  lastLedger,
 | 
						|
}
 |