1
+ import { BigNumberCoder } from '@fuel-ts/abi-coder' ;
2
+ import { sha256 } from '@fuel-ts/hasher' ;
1
3
import { concat } from '@fuel-ts/utils' ;
2
4
import * as asm from '@fuels/vm-asm' ;
3
5
@@ -7,16 +9,61 @@ const REG_START_OF_LOADED_CODE = 0x11;
7
9
const REG_GENERAL_USE = 0x12 ;
8
10
const WORD_SIZE = 8 ; // size in bytes
9
11
10
- export function getConfigurableOffset ( binary : Uint8Array ) : number {
11
- // Extract 8 bytes starting from index 16 (similar to binary[16..24] in Rust)
12
- const OFFSET_INDEX = 16 ;
13
- const dataView = new DataView ( binary . buffer , OFFSET_INDEX , 8 ) ;
12
+ export const DATA_OFFSET_INDEX = 8 ;
13
+ export const CONFIGURABLE_OFFSET_INDEX = 16 ;
14
+
15
+ /**
16
+ * Get the offset of the data section in the bytecode
17
+ *
18
+ * @param bytecode - The bytecode to get the offset from
19
+ * @returns The offset of the data section
20
+ */
21
+ export function getBytecodeDataOffset ( bytecode : Uint8Array ) : number {
22
+ const [ offset ] = new BigNumberCoder ( 'u64' ) . decode ( bytecode , DATA_OFFSET_INDEX ) ;
23
+ return offset . toNumber ( ) ;
24
+ }
25
+
26
+ /**
27
+ * Get the offset of the configurable section in the bytecode
28
+ *
29
+ * @param bytecode - The bytecode to get the offset from
30
+ * @returns The offset of the configurable section
31
+ */
32
+ export function getBytecodeConfigurableOffset ( bytecode : Uint8Array ) : number {
33
+ const [ offset ] = new BigNumberCoder ( 'u64' ) . decode ( bytecode , CONFIGURABLE_OFFSET_INDEX ) ;
34
+ return offset . toNumber ( ) ;
35
+ }
14
36
15
- // Read the value as a 64-bit big-endian unsigned integer
16
- const dataOffset = dataView . getBigUint64 ( 0 , false ) ; // false means big-endian
37
+ /**
38
+ * Takes bytecode and generates it's associated bytecode ID.
39
+ *
40
+ * The bytecode ID is a hash of the bytecode when sliced at the configurable offset. This
41
+ * superseded legacy blob IDs when uploading blobs for scripts and predicates so that
42
+ * the bytecode ID is equal to the legacy blob ID. Therefore blobs can be used for ABI verification.
43
+ *
44
+ * @param bytecode - The bytecode to get the id from
45
+ * @returns The id of the bytecode
46
+ */
47
+ export function getBytecodeId ( bytecode : Uint8Array ) : string {
48
+ const configurableOffset = getBytecodeConfigurableOffset ( bytecode ) ;
49
+ const byteCodeWithoutConfigurableSection = bytecode . slice ( 0 , configurableOffset ) ;
50
+
51
+ return sha256 ( byteCodeWithoutConfigurableSection ) ;
52
+ }
17
53
18
- // Convert the BigInt to a regular number (safe as long as the offset is within Number.MAX_SAFE_INTEGER)
19
- return Number ( dataOffset ) ;
54
+ /**
55
+ * Takes bytecode and generates it's associated legacy blob ID.
56
+ *
57
+ * The legacy blob ID is a hash of the bytecode when sliced at the data section offset.
58
+ *
59
+ * @param bytecode - The bytecode to get the id from
60
+ * @returns The id of the bytecode
61
+ */
62
+ export function getLegacyBlobId ( bytecode : Uint8Array ) : string {
63
+ const dataOffset = getBytecodeDataOffset ( bytecode ) ;
64
+ const byteCodeWithoutDataSection = bytecode . slice ( 0 , dataOffset ) ;
65
+
66
+ return sha256 ( byteCodeWithoutDataSection ) ;
20
67
}
21
68
22
69
export function getPredicateScriptLoaderInstructions (
@@ -100,7 +147,7 @@ export function getPredicateScriptLoaderInstructions(
100
147
asm . jmp ( REG_START_OF_LOADED_CODE ) ,
101
148
] ;
102
149
103
- const offset = getConfigurableOffset ( originalBinary ) ;
150
+ const offset = getBytecodeConfigurableOffset ( originalBinary ) ;
104
151
105
152
// if the binary length is smaller than the offset
106
153
if ( originalBinary . length < offset ) {
0 commit comments