Skip to content

Commit

Permalink
feat: use configurable offset for blob ID (#3631)
Browse files Browse the repository at this point in the history
* feat: use configurable offset for blob ID

* chore: changeset

* chore: update changeset

* chore: revert recipe stuff
danielbate authored Jan 28, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 1511d8e commit ec84b8a
Showing 3 changed files with 23 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/new-seas-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fuel-ts/account": patch
---

feat: use configurable offset for blob ID
14 changes: 7 additions & 7 deletions packages/account/src/utils/deployScriptOrPredicate.ts
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ import type { Account } from '../account';
import { BlobTransactionRequest, calculateGasFee, TransactionStatus } from '../providers';

import {
getDataOffset,
getConfigurableOffset,
getPredicateScriptLoaderInstructions,
} from './predicate-script-loader-instructions';

@@ -63,25 +63,25 @@ export async function deployScriptOrPredicate<T>({
abi,
loaderInstanceCallback,
}: Deployer<T>) {
const dataSectionOffset = getDataOffset(arrayify(bytecode));
const byteCodeWithoutDataSection = bytecode.slice(0, dataSectionOffset);
const configurableOffset = getConfigurableOffset(arrayify(bytecode));
const byteCodeWithoutConfigurableSection = bytecode.slice(0, configurableOffset);

// Generate the associated create tx for the loader contract
const blobId = hash(byteCodeWithoutDataSection);
const blobId = hash(byteCodeWithoutConfigurableSection);

const blobTxRequest = new BlobTransactionRequest({
blobId,
witnessIndex: 0,
witnesses: [byteCodeWithoutDataSection],
witnesses: [byteCodeWithoutConfigurableSection],
});

const { loaderBytecode, blobOffset } = getPredicateScriptLoaderInstructions(
arrayify(bytecode),
arrayify(blobId)
);

const configurableOffsetDiff = byteCodeWithoutDataSection.length - (blobOffset || 0);
const newAbi = adjustConfigurableOffsets(abi, configurableOffsetDiff);
const newConfigurableOffsetDiff = byteCodeWithoutConfigurableSection.length - (blobOffset || 0);
const newAbi = adjustConfigurableOffsets(abi, newConfigurableOffsetDiff);

const blobExists = (await deployer.provider.getBlobs([blobId])).length > 0;

22 changes: 11 additions & 11 deletions packages/account/src/utils/predicate-script-loader-instructions.ts
Original file line number Diff line number Diff line change
@@ -7,9 +7,9 @@ const REG_START_OF_LOADED_CODE = 0x11;
const REG_GENERAL_USE = 0x12;
const WORD_SIZE = 8; // size in bytes

export function getDataOffset(binary: Uint8Array): number {
// Extract 8 bytes starting from index 8 (similar to binary[8..16] in Rust)
const OFFSET_INDEX = 8;
export function getConfigurableOffset(binary: Uint8Array): number {
// Extract 8 bytes starting from index 16 (similar to binary[16..24] in Rust)
const OFFSET_INDEX = 16;
const dataView = new DataView(binary.buffer, OFFSET_INDEX, 8);

// Read the value as a 64-bit big-endian unsigned integer
@@ -100,7 +100,7 @@ export function getPredicateScriptLoaderInstructions(
asm.jmp(REG_START_OF_LOADED_CODE),
];

const offset = getDataOffset(originalBinary);
const offset = getConfigurableOffset(originalBinary);

// if the binary length is smaller than the offset
if (originalBinary.length < offset) {
@@ -109,11 +109,11 @@ export function getPredicateScriptLoaderInstructions(
);
}

// Extract the data section from the binary (slice from the offset onwards)
const dataSection = originalBinary.slice(offset);
// Extract the configurable section from the binary (slice from the configurable offset onwards)
const configurableSection = originalBinary.slice(offset);

// Check if the data section is non-empty
if (dataSection.length > 0) {
// Check if the configurable section is non-empty
if (configurableSection.length > 0) {
// Get the number of instructions (assuming it won't exceed u16::MAX)
const numOfInstructions = getInstructions(0).length;
if (numOfInstructions > 65535) {
@@ -133,7 +133,7 @@ export function getPredicateScriptLoaderInstructions(
// Convert data section length to big-endian 8-byte array
const dataSectionLenBytes = new Uint8Array(8);
const dataView = new DataView(dataSectionLenBytes.buffer);
dataView.setBigUint64(0, BigInt(dataSection.length), false); // false for big-endian
dataView.setBigUint64(0, BigInt(configurableSection.length), false); // false for big-endian

// Combine the instruction bytes, blob bytes, data section length, and the data section
const loaderBytecode = new Uint8Array([
@@ -143,11 +143,11 @@ export function getPredicateScriptLoaderInstructions(
]);

return {
loaderBytecode: concat([loaderBytecode, dataSection]),
loaderBytecode: concat([loaderBytecode, configurableSection]),
blobOffset: loaderBytecode.length,
};
}
// Handle case where there is no data section
// Handle case where there is no configurable section
const numOfInstructions = getInstructionsNoDataSection(0).length;
if (numOfInstructions > 65535) {
throw new Error('Too many instructions, exceeding u16::MAX.');

0 comments on commit ec84b8a

Please sign in to comment.