Passed
Push — feature/scrutinizer ( a7c264...31e6b8 )
by Yuri
01:43
created

ReceiptParser.getTransactionIdsFromReceiptString   A

Complexity

Conditions 2

Size

Total Lines 9
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 9
ccs 4
cts 4
cp 1
c 0
b 0
f 0
rs 10
cc 2
crap 2
1 1
import { fromBER } from 'asn1js'
2
3
interface Block {
4
  blockName: string
5
  valueBlock: {
6
    valueHex?: string
7
    value?: Block[] | string
8
  }
9
}
10
11
export interface TransactionIds {
12
  transactionIds: string[]
13
  originalTransactionIds: string[]
14
}
15
16
/**
17
 * Parses a receipt string and extracts the transaction IDs from it.
18
 * Warning! This class does not validate the receipt string, only extracts them.
19
 */
20 1
export class ReceiptParser {
21 2
  constructor (private readonly receiptString: string) {}
22
23
  static getTransactionIdsFromBlock (block: Block): TransactionIds | null {
24 2084
    const { valueBlock } = block
25
26 2084
    if (!valueBlock || !Array.isArray(valueBlock.value)) {
27 1110
      return null
28
    }
29
30 974
    if (valueBlock.value.length === 3) {
31 328
      const result = this.extractTransactionIds(valueBlock.value)
32 328
      if (result) return result
33
    }
34
35 946
    const result: TransactionIds = { transactionIds: [], originalTransactionIds: [] }
36
37 946
    for (const innerBlock of valueBlock.value) {
38 2082
      const innerIds = this.getTransactionIdsFromBlock(innerBlock)
39 2082
      if (innerIds) {
40 972
        result.transactionIds.push(...innerIds.transactionIds)
41 972
        result.originalTransactionIds.push(...innerIds.originalTransactionIds)
42
      }
43
    }
44
45
    // Deduplicate the IDs
46 946
    result.transactionIds = [...new Set(result.transactionIds)]
47 946
    result.originalTransactionIds = [...new Set(result.originalTransactionIds)]
48
49 946
    return result
50
  }
51
52
  static getTransactionIdsFromReceiptString (receiptString: string): TransactionIds | null {
53 3
    const { result } = fromBER(Buffer.from(receiptString, 'base64'))
54
55 3
    if (result.error) {
56 1
      throw new Error(`Error parsing receipt: ${result.error}`)
57
    }
58
59 2
    return this.getTransactionIdsFromBlock(result.toJSON() as Block)
60
  }
61
62
  /**
63
   * The transaction ID is encoded as an INTEGER with the value 0x06a7
64
   */
65
  private static isTransactionIdBlock (block: Block): boolean {
66 328
    return block.blockName === 'INTEGER' && block.valueBlock.valueHex === '06a7'
67
  }
68
69
  /**
70
   * The original transaction ID is encoded as an INTEGER with the value 0x06a9
71
   */
72
  private static isOriginalTransactionIdBlock (block: Block): boolean {
73 314
    return block.blockName === 'INTEGER' && block.valueBlock.valueHex === '06a9'
74
  }
75
76
  private static extractIdFromBlock (block: Block): string | null {
77 28
    if (!Array.isArray(block.valueBlock.value)) {
78
      return null
79
    }
80
81
    // The transaction ID is encoded as an OCTET STRING containing a UTF8String
82 28
    if (block.blockName === 'OCTET STRING' && block.valueBlock.value[0].blockName === 'UTF8String') {
83 28
      return block.valueBlock.value[0].valueBlock.value as string
84
    }
85
86
    return null
87
  }
88
89
  private static extractTransactionIds (blocks: Block[]): TransactionIds | null {
90 328
    const [firstBlock, , lastBlock] = blocks
91 328
    const result: TransactionIds = { transactionIds: [], originalTransactionIds: [] }
92
93 328
    if (this.isTransactionIdBlock(firstBlock)) {
94 14
      const id = this.extractIdFromBlock(lastBlock)
95 14
      if (id) result.transactionIds.push(id)
96 314
    } else if (this.isOriginalTransactionIdBlock(firstBlock)) {
97 14
      const id = this.extractIdFromBlock(lastBlock)
98 14
      if (id) result.originalTransactionIds.push(id)
99
    } else {
100 300
      return null
101
    }
102
103 28
    return result
104
  }
105
106
  getTransactionIds (): TransactionIds | null {
107 2
    return ReceiptParser.getTransactionIdsFromReceiptString(this.receiptString)
108
  }
109
}
110