1
+ function processTVMSliceReadAddress ( base64String ) {
2
+ let buffer = decodeBase64 ( base64String ) ;
3
+ let { offset, root, index, cellData } = parseBoc ( buffer ) ;
4
+ let { wc, addressHash } = parseAddress ( buffer , offset ) ;
5
+ return serializeAddress ( wc , addressHash ) ;
6
+ }
7
+
8
+ function decodeBase64 ( base64String ) {
9
+ const buffer = Buffer . from ( base64String , 'base64' ) ;
10
+ return buffer ;
11
+ }
12
+
13
+ function parseBoc ( buffer ) {
14
+ if ( buffer . length < 4 ) {
15
+ throw new Error ( "Buffer is too short to contain magic bytes" ) ;
16
+ }
17
+
18
+ const magic = buffer . readUInt32BE ( 0 ) ;
19
+ if ( magic !== 0xb5ee9c72 ) {
20
+ throw new Error ( "Invalid magic" ) ;
21
+ }
22
+
23
+ let offset = 4 ;
24
+
25
+ let hasIdx = ( buffer [ offset ] >> 7 ) & 1 ;
26
+ let hasCrc32c = ( buffer [ offset ] >> 6 ) & 1 ;
27
+ let hasCacheBits = ( buffer [ offset ] >> 5 ) & 1 ;
28
+ let flags = ( buffer [ offset ] >> 3 ) & 0b11 ; // 2 bits
29
+ let size = buffer [ offset ] & 0b111 ; // 3 bits
30
+ offset ++ ;
31
+
32
+ let offBytes = buffer . readUInt8 ( offset ) ;
33
+ offset ++ ;
34
+
35
+ let cells = buffer . readUIntBE ( offset , size ) ;
36
+ offset += size ;
37
+
38
+ let roots = buffer . readUIntBE ( offset , size ) ;
39
+ offset += size ;
40
+
41
+ let absent = buffer . readUIntBE ( offset , size ) ;
42
+ offset += size ;
43
+
44
+ let totalCellSize = buffer . readUIntBE ( offset , offBytes ) ;
45
+ offset += offBytes ;
46
+
47
+ let root = [ ] ;
48
+ for ( let i = 0 ; i < roots ; i ++ ) {
49
+ root . push ( buffer . readUIntBE ( offset , size ) ) ;
50
+ offset += size ;
51
+ }
52
+
53
+ let index = null ;
54
+ if ( hasIdx ) {
55
+ index = buffer . slice ( offset , offset + cells * offBytes ) ;
56
+ offset += cells * offBytes ;
57
+ }
58
+
59
+ let cellData = buffer . slice ( offset , offset + totalCellSize ) ;
60
+ offset += totalCellSize ;
61
+
62
+ return { offset, root, index, cellData } ;
63
+ }
64
+
65
+ function parseAddress ( buffer , offset ) {
66
+ const wcByteOffset = 13 ;
67
+ const wcBitsOffset = 3 ;
68
+ let reader = new BitReader ( buffer , wcByteOffset , wcBitsOffset ) ;
69
+
70
+ let wc = ( reader . readBits ( 5 ) << 3 ) | ( reader . readBits ( 3 ) ) ;
71
+ let addressHash = reader . readBytes ( 32 ) ;
72
+
73
+ return { wc, addressHash, offset : reader . byteOffset } ;
74
+ }
75
+
76
+ function serializeAddress ( wc , addressHash ) {
77
+ const bounceableTag = 0x11 ;
78
+ let fullAddress = Buffer . alloc ( 36 ) ;
79
+ fullAddress [ 0 ] = bounceableTag ;
80
+ fullAddress [ 1 ] = wc ;
81
+ addressHash . copy ( fullAddress , 2 ) ;
82
+
83
+ let crc16 = computeCRC16 ( fullAddress . slice ( 0 , 34 ) ) ;
84
+ fullAddress . writeUInt16BE ( crc16 , 34 ) ;
85
+
86
+ return fullAddress . toString ( 'base64' ) . replace ( / \+ / g, '-' ) . replace ( / \/ / g, '_' ) ;
87
+ }
88
+
89
+ function computeCRC16 ( buffer ) {
90
+ let crc = 0x0000 ;
91
+ let polynomial = 0x1021 ;
92
+
93
+ for ( let i = 0 ; i < buffer . length ; i ++ ) {
94
+ crc ^= buffer [ i ] << 8 ;
95
+ for ( let j = 0 ; j < 8 ; j ++ ) {
96
+ if ( crc & 0x8000 ) {
97
+ crc = ( crc << 1 ) ^ polynomial ;
98
+ } else {
99
+ crc <<= 1 ;
100
+ }
101
+ }
102
+ crc &= 0xFFFF ;
103
+ }
104
+ return crc ;
105
+ }
106
+
107
+ class BitReader {
108
+ constructor ( buffer , startByte = 0 , startBit = 0 ) {
109
+ this . buffer = buffer ;
110
+ this . byteOffset = startByte ;
111
+ this . bitOffset = startBit ;
112
+ }
113
+
114
+ readBits ( n ) {
115
+ let value = 0 ;
116
+
117
+ for ( let i = 0 ; i < n ; i ++ ) {
118
+ if ( this . byteOffset >= this . buffer . length ) {
119
+ throw new Error ( "Buffer overflow while reading bits" ) ;
120
+ }
121
+
122
+ let bit = ( this . buffer [ this . byteOffset ] >> ( 7 - this . bitOffset ) ) & 1 ;
123
+ value = ( value << 1 ) | bit ;
124
+
125
+ this . bitOffset ++ ;
126
+ if ( this . bitOffset === 8 ) {
127
+ this . bitOffset = 0 ;
128
+ this . byteOffset ++ ;
129
+ }
130
+ }
131
+ return value ;
132
+ }
133
+
134
+ readBytes ( n ) {
135
+ let bytes = Buffer . alloc ( n ) ;
136
+ for ( let i = 0 ; i < n ; i ++ ) {
137
+ bytes [ i ] = this . readBits ( 8 ) ;
138
+ }
139
+ return bytes ;
140
+ }
141
+ }
142
+
143
+ module . exports = { processTVMSliceReadAddress }
0 commit comments