DeFiCh/jellyfish

View on GitHub
apps/whale-api/src/module.indexer/model/transaction.vin.ts

Summary

Maintainability
A
2 hrs
Test Coverage
import { Injectable } from '@nestjs/common'
import { defid, Indexer, RawBlock } from './_abstract'
import { TransactionVin, TransactionVinMapper } from '../../module.model/transaction.vin'
import { TransactionVout } from '../../module.model/transaction.vout'
import { HexEncoder } from '../../module.model/_hex.encoder'
import { VoutFinder } from './_vout_finder'
import { NotFoundIndexerError } from '../error'
import { checkIfEvmTx } from '../helper'

@Injectable()
export class TransactionVinIndexer extends Indexer {
  constructor (
    private readonly vinMapper: TransactionVinMapper,
    private readonly voutFinder: VoutFinder
  ) {
    super()
  }

  async index (block: RawBlock): Promise<void> {
    for (const txn of block.tx) {
      const isEvmTx = checkIfEvmTx(txn)

      for (const vin of txn.vin) {
        if (isEvmTx) {
          continue
        }

        if (vin.coinbase !== undefined) {
          await this.vinMapper.put(this.map(txn, vin, undefined))
        } else {
          const vout = await this.voutFinder.findVout(block, vin.txid, vin.vout)
          if (vout === undefined) {
            throw new NotFoundIndexerError('index', 'TransactionVout', `${vin.txid} - ${vin.vout}`)
          }
          await this.vinMapper.put(this.map(txn, vin, vout))
        }
      }
    }
  }

  async invalidate (block: RawBlock): Promise<void> {
    for (const txn of block.tx) {
      for (const vin of txn.vin) {
        await this.vinMapper.delete(this.mapId(txn, vin))
      }
    }
  }

  map (txn: defid.Transaction, vin: defid.Vin, vout?: TransactionVout): TransactionVin {
    return {
      id: this.mapId(txn, vin),
      txid: txn.txid,
      coinbase: vin.coinbase,
      vout: vout !== undefined
        ? {
            id: vout.id,
            txid: vout.txid,
            n: vout.n,
            value: vout.value,
            tokenId: vout.tokenId,
            script: {
              hex: vout.script.hex
            }
          }
        : undefined,
      script: vin.scriptSig !== undefined
        ? {
            hex: vin.scriptSig.hex
          }
        : undefined,
      txInWitness: vin.txinwitness,
      sequence: vin.sequence
    }
  }

  /**
   * non coinbase: txn.txid + vout.txid + vout.n (4 bytes encoded hex)
   *     coinbase: txn.txid + '00'
   */
  mapId (txn: defid.Transaction, vin: defid.Vin): string {
    if (vin.coinbase !== undefined) {
      return `${txn.txid}00`
    }
    return txn.txid + vin.txid + HexEncoder.encodeVoutIndex(vin.vout)
  }
}