Skip to content

Commit

Permalink
refactor: purge the usage of the hardcoded constant VM_TX_MEMORY (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhaiwat10 authored Oct 5, 2023
1 parent c49f966 commit ddf1bd2
Show file tree
Hide file tree
Showing 15 changed files with 63 additions and 27 deletions.
8 changes: 8 additions & 0 deletions .changeset/moody-hats-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@fuel-ts/abi-coder": patch
"@fuel-ts/predicate": patch
"@fuel-ts/program": patch
"@fuel-ts/providers": patch
---

refactor: purge the usage of the hardcoded constant `VM_TX_MEMORY`
7 changes: 0 additions & 7 deletions packages/abi-coder/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@ export const calculateVmTxMemory = ({ maxInputs }: { maxInputs: number }) =>
// Asset ID/Balance coin input pairs
maxInputs * (ASSET_ID_LEN + WORD_SIZE);

// VM_TX_MEMORY = 10240
export const VM_TX_MEMORY =
BYTES_32 + // Tx ID
WORD_SIZE + // Tx size
// Asset ID/Balance coin input pairs
MAX_INPUTS * (ASSET_ID_LEN + WORD_SIZE);

// SCRIPT_FIXED_SIZE = 104
export const SCRIPT_FIXED_SIZE =
WORD_SIZE + // Identifier
Expand Down
1 change: 0 additions & 1 deletion packages/abi-coder/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export type { FunctionFragment } from './function-fragment';
export { Interface } from './interface';
export { JsonAbi } from './json-abi';
export {
VM_TX_MEMORY,
SCRIPT_FIXED_SIZE,
INPUT_COIN_FIXED_SIZE,
WORD_SIZE,
Expand Down
5 changes: 4 additions & 1 deletion packages/predicate/src/predicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
Interface,
INPUT_COIN_FIXED_SIZE,
SCRIPT_FIXED_SIZE,
VM_TX_MEMORY,
WORD_SIZE,
calculateVmTxMemory,
} from '@fuel-ts/abi-coder';
import { Address } from '@fuel-ts/address';
import { ErrorCode, FuelError } from '@fuel-ts/errors';
Expand Down Expand Up @@ -113,6 +113,9 @@ export class Predicate<ARGS extends InputValue[]> extends Account implements Abs
const mainFn = this.interface?.functions.main;
const paddedCode = new ByteArrayCoder(this.bytes.length).encode(this.bytes);

const VM_TX_MEMORY = calculateVmTxMemory({
maxInputs: this.provider.getChain().consensusParameters.maxInputs.toNumber(),
});
const OFFSET =
VM_TX_MEMORY + SCRIPT_FIXED_SIZE + INPUT_COIN_FIXED_SIZE + WORD_SIZE + paddedCode.byteLength;

Expand Down
9 changes: 6 additions & 3 deletions packages/program/src/contract-call-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { WORD_SIZE, U64Coder, B256Coder, ASSET_ID_LEN, CONTRACT_ID_LEN } from '@
import { BaseAssetId, ZeroBytes32 } from '@fuel-ts/address/configs';
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import type { AbstractAddress } from '@fuel-ts/interfaces';
import type { BN } from '@fuel-ts/math';
import { bn, toNumber } from '@fuel-ts/math';
import type {
CallResult,
Expand All @@ -19,8 +20,8 @@ import type { EncodedScriptCall, ScriptResult } from './script-request';
import {
decodeCallResult,
ScriptRequest,
SCRIPT_DATA_BASE_OFFSET,
POINTER_DATA_OFFSET,
calculateScriptDataBaseOffset,
} from './script-request';
import type { ContractCall, InvocationScopeLike } from './types';

Expand Down Expand Up @@ -202,7 +203,8 @@ const getFunctionOutputInfos = (functionScopes: InvocationScopeLike[]): CallOutp
});

export const getContractCallScript = (
functionScopes: InvocationScopeLike[]
functionScopes: InvocationScopeLike[],
maxInputs: BN
): ScriptRequest<ContractCall[], Uint8Array[]> =>
new ScriptRequest<ContractCall[], Uint8Array[]>(
// Script to call the contract, start with stub size matching length of calls
Expand All @@ -224,7 +226,8 @@ export const getContractCallScript = (
const paddedInstructionsLength = callInstructionsLength + paddingLength;

// get total data offset AFTER all scripts
const dataOffset = SCRIPT_DATA_BASE_OFFSET + paddedInstructionsLength;
const dataOffset =
calculateScriptDataBaseOffset(maxInputs.toNumber()) + paddedInstructionsLength;

// The data for each call is ordered into segments
const paramOffsets: CallOpcodeParamsOffset[] = [];
Expand Down
9 changes: 5 additions & 4 deletions packages/program/src/functions/base-invocation-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ export class BaseInvocationScope<TReturn = any> {
* @returns An array of contract calls.
*/
protected get calls() {
const script = getContractCallScript(this.functionInvocationScopes);
const provider = this.getProvider();
const consensusParams = provider.getChain().consensusParameters;
if (!consensusParams) {
Expand All @@ -85,17 +84,19 @@ export class BaseInvocationScope<TReturn = any> {
'Provider chain info cache is empty. Please make sure to initialize the `Provider` properly by running `await Provider.create()``'
);
}
const maxInputs = consensusParams.maxInputs.toNumber();
const maxInputs = consensusParams.maxInputs;
const script = getContractCallScript(this.functionInvocationScopes, maxInputs);
return this.functionInvocationScopes.map((funcScope) =>
createContractCall(funcScope, script.getScriptDataOffset(maxInputs))
createContractCall(funcScope, script.getScriptDataOffset(maxInputs.toNumber()))
);
}

/**
* Updates the script request with the current contract calls.
*/
protected updateScriptRequest() {
const contractCallScript = getContractCallScript(this.functionInvocationScopes);
const maxInputs = (this.program.provider as Provider).getChain().consensusParameters.maxInputs;
const contractCallScript = getContractCallScript(this.functionInvocationScopes, maxInputs);
this.transactionRequest.setScript(contractCallScript, this.calls);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/program/src/script-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import type { BytesLike } from '@ethersproject/bytes';
import { arrayify } from '@ethersproject/bytes';
import {
VM_TX_MEMORY,
ASSET_ID_LEN,
CONTRACT_ID_LEN,
SCRIPT_FIXED_SIZE,
Expand All @@ -26,7 +25,8 @@ import { ReceiptType } from '@fuel-ts/transactions';
import { ScriptResultDecoderError } from './errors';
import type { CallConfig } from './types';

export const SCRIPT_DATA_BASE_OFFSET = VM_TX_MEMORY + SCRIPT_FIXED_SIZE;
export const calculateScriptDataBaseOffset = (maxInputs: number) =>
SCRIPT_FIXED_SIZE + calculateVmTxMemory({ maxInputs });
export const POINTER_DATA_OFFSET =
WORD_SIZE + ASSET_ID_LEN + CONTRACT_ID_LEN + WORD_SIZE + WORD_SIZE;
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export class TransactionResponse {
const receipts = transaction.receipts?.map(processGqlReceipt) || [];

const { gasPerByte, gasPriceFactor } = this.provider.getGasConfig();
const maxInputs = this.provider.getChain().consensusParameters.maxInputs;

const transactionSummary = assembleTransactionSummary<TTransactionType>({
id: this.id,
Expand All @@ -187,6 +188,7 @@ export class TransactionResponse {
gasPerByte: bn(gasPerByte),
gasPriceFactor: bn(gasPriceFactor),
abiMap: contractsAbiMap,
maxInputs,
});

return transactionSummary;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('TransactionSummary', () => {
const id = '0x2bfbebca58da94ba3ee258698c9be5884e2874688bdffa29cb535cf05d665215';
const gasPerByte = bn(2);
const gasPriceFactor = bn(3);
const maxInputs = bn(255);
const transaction = MOCK_TRANSACTION;
const transactionBytes = arrayify(MOCK_TRANSACTION_RAWPAYLOAD);
const receipts: TransactionResultReceipt[] = [
Expand All @@ -43,6 +44,7 @@ describe('TransactionSummary', () => {
transactionBytes,
receipts,
gqlTransactionStatus: status,
maxInputs,
});

expect(transactionSummary).toMatchObject(expected);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface AssembleTransactionSummaryParams {
gqlTransactionStatus?: GraphqlTransactionStatus;
receipts: TransactionResultReceipt[];
abiMap?: AbiMap;
maxInputs: BN;
}

/** @hidden */
Expand All @@ -41,6 +42,7 @@ export function assembleTransactionSummary<TTransactionType = void>(
id,
gqlTransactionStatus,
abiMap = {},
maxInputs,
} = params;

const gasPrice = bn(transaction.gasPrice);
Expand All @@ -62,6 +64,7 @@ export function assembleTransactionSummary<TTransactionType = void>(
receipts,
rawPayload: hexlify(transactionBytes),
abiMap,
maxInputs,
});

const typeName = getTransactionTypeName(transaction.type);
Expand Down
12 changes: 8 additions & 4 deletions packages/providers/src/transaction-summary/call.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Interface, VM_TX_MEMORY, type JsonAbi } from '@fuel-ts/abi-coder';
import { Interface, type JsonAbi, calculateVmTxMemory } from '@fuel-ts/abi-coder';
import type { BN } from '@fuel-ts/math';
import { bn } from '@fuel-ts/math';
import type { ReceiptCall } from '@fuel-ts/transactions';

type GetFunctionCallProps = {
abi: JsonAbi;
receipt: ReceiptCall;
rawPayload?: string;
maxInputs: BN;
};

export const getFunctionCall = ({ abi, receipt, rawPayload }: GetFunctionCallProps) => {
export const getFunctionCall = ({ abi, receipt, rawPayload, maxInputs }: GetFunctionCallProps) => {
const abiInterface = new Interface(abi);
const callFunctionSelector = receipt.param1.toHex(8);
const functionFragment = abiInterface.getFunction(callFunctionSelector);
Expand All @@ -19,8 +21,10 @@ export const getFunctionCall = ({ abi, receipt, rawPayload }: GetFunctionCallPro
// if has more than 1 input or input type is bigger than 8 bytes, then it's a pointer to data
if (functionFragment.isInputDataPointer) {
if (rawPayload) {
// calculate offset to get function params from rawPayload. should also consider vm offset: VM_TX_MEMORY
const argsOffset = bn(receipt.param2).sub(VM_TX_MEMORY).toNumber();
// calculate offset to get function params from rawPayload. should also consider vm offset
const argsOffset = bn(receipt.param2)
.sub(calculateVmTxMemory({ maxInputs: maxInputs.toNumber() }))
.toNumber();

// slice(2) to remove first 0x, then slice again to remove offset and get only args
encodedArgs = `0x${rawPayload.slice(2).slice(argsOffset * 2)}`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export async function getTransactionSummary<TTransactionType = void>(
const receipts = gqlTransaction.receipts?.map(processGqlReceipt) || [];

const {
consensusParameters: { gasPerByte, gasPriceFactor },
} = await provider.getChain();
consensusParameters: { gasPerByte, gasPriceFactor, maxInputs },
} = provider.getChain();

const transactionInfo = assembleTransactionSummary<TTransactionType>({
id: gqlTransaction.id,
Expand All @@ -58,6 +58,7 @@ export async function getTransactionSummary<TTransactionType = void>(
gasPerByte: bn(gasPerByte),
gasPriceFactor: bn(gasPriceFactor),
abiMap,
maxInputs,
});

return {
Expand All @@ -81,6 +82,7 @@ export async function getTransactionSummaryFromRequest<TTransactionType = void>(
const { receipts } = await provider.call(transactionRequest);

const { gasPerByte, gasPriceFactor } = provider.getGasConfig();
const maxInputs = provider.getChain().consensusParameters.maxInputs;

const transaction = transactionRequest.toTransaction();
const transactionBytes = transactionRequest.toTransactionBytes();
Expand All @@ -92,6 +94,7 @@ export async function getTransactionSummaryFromRequest<TTransactionType = void>(
abiMap,
gasPerByte,
gasPriceFactor,
maxInputs,
});

return transactionSummary;
Expand Down Expand Up @@ -119,8 +122,8 @@ export async function getTransactionsSummaries(
const { edges, pageInfo } = transactionsByOwner;

const {
consensusParameters: { gasPerByte, gasPriceFactor },
} = await provider.getChain();
consensusParameters: { gasPerByte, gasPriceFactor, maxInputs },
} = provider.getChain();

const transactions = edges.map((edge) => {
const { node: gqlTransaction } = edge;
Expand All @@ -140,6 +143,7 @@ export async function getTransactionsSummaries(
abiMap,
gasPerByte,
gasPriceFactor,
maxInputs,
});

const output: TransactionResult = {
Expand Down
9 changes: 9 additions & 0 deletions packages/providers/src/transaction-summary/operations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ describe('operations', () => {
inputs: [MOCK_INPUT_CONTRACT, MOCK_INPUT_COIN],
outputs: [MOCK_OUTPUT_CONTRACT, MOCK_OUTPUT_VARIABLE, MOCK_OUTPUT_CHANGE],
receipts,
maxInputs: bn(255),
});

expect(operations.length).toEqual(1);
Expand Down Expand Up @@ -143,6 +144,7 @@ describe('operations', () => {
'0x0a98320d39c03337401a4e46263972a9af6ce69ec2f35a5420b1bd35784c74b1': CONTRACT_CALL_ABI,
},
rawPayload: MOCK_TRANSACTION_RAWPAYLOAD,
maxInputs: bn(255),
});

expect(operations.length).toEqual(1);
Expand All @@ -154,6 +156,7 @@ describe('operations', () => {
inputs: [],
outputs: [MOCK_OUTPUT_COIN, MOCK_OUTPUT_CHANGE],
receipts: [MOCK_RECEIPT_RETURN, MOCK_RECEIPT_SCRIPT_RESULT],
maxInputs: bn(255),
});

expect(operations.length).toEqual(0);
Expand Down Expand Up @@ -452,6 +455,7 @@ describe('operations', () => {
MOCK_RECEIPT_RETURN_DATA_2,
MOCK_RECEIPT_SCRIPT_RESULT,
],
maxInputs: bn(255),
});
expect(operations.length).toEqual(2);
expect(operations).toStrictEqual(expected);
Expand Down Expand Up @@ -501,6 +505,7 @@ describe('operations', () => {
inputs: [MOCK_INPUT_CONTRACT, MOCK_INPUT_COIN],
outputs: [MOCK_OUTPUT_CONTRACT, MOCK_OUTPUT_VARIABLE, MOCK_OUTPUT_CHANGE],
receipts: receiptsCallNoAmount,
maxInputs: bn(255),
});
expect(operations.length).toEqual(2);
expect(operations[0]).toStrictEqual(operationsCallNoAmount); // contract call
Expand Down Expand Up @@ -530,6 +535,7 @@ describe('operations', () => {
inputs: [MOCK_INPUT_COIN, MOCK_INPUT_COIN],
outputs: [MOCK_OUTPUT_COIN, MOCK_OUTPUT_CHANGE],
receipts: [MOCK_RECEIPT_RETURN, MOCK_RECEIPT_SCRIPT_RESULT],
maxInputs: bn(255),
});
expect(operations.length).toEqual(1);

Expand Down Expand Up @@ -560,6 +566,7 @@ describe('operations', () => {
inputs: [MOCK_INPUT_MESSAGE, MOCK_INPUT_MESSAGE],
outputs: [MOCK_OUTPUT_COIN, MOCK_OUTPUT_CHANGE],
receipts: [MOCK_RECEIPT_RETURN, MOCK_RECEIPT_SCRIPT_RESULT],
maxInputs: bn(255),
});

expect(operations.length).toEqual(1);
Expand Down Expand Up @@ -589,6 +596,7 @@ describe('operations', () => {
inputs: [],
outputs: [MOCK_OUTPUT_COIN],
receipts: [],
maxInputs: bn(255),
});

expect(operations.length).toEqual(1);
Expand All @@ -612,6 +620,7 @@ describe('operations', () => {
inputs: [MOCK_INPUT_COIN, MOCK_INPUT_COIN],
outputs: [MOCK_OUTPUT_CONTRACT_CREATED, MOCK_OUTPUT_CHANGE],
receipts: [],
maxInputs: bn(255),
});

expect(operations.length).toEqual(1);
Expand Down
6 changes: 5 additions & 1 deletion packages/providers/src/transaction-summary/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,10 @@ export function getContractCallOperations({
receipts,
abiMap,
rawPayload,
maxInputs,
}: InputOutputParam &
ReceiptParam &
Pick<GetOperationParams, 'abiMap'> &
Pick<GetOperationParams, 'abiMap' | 'maxInputs'> &
RawPayloadParam): Operation[] {
const contractCallReceipts = getReceiptsCall(receipts);
const contractOutputs = getOutputsContract(outputs);
Expand All @@ -272,6 +273,7 @@ export function getContractCallOperations({
abi,
receipt,
rawPayload,
maxInputs,
})
);
}
Expand Down Expand Up @@ -406,6 +408,7 @@ export function getOperations({
receipts,
abiMap,
rawPayload,
maxInputs,
}: GetOperationParams): Operation[] {
if (isTypeCreate(transactionType)) {
return [
Expand All @@ -423,6 +426,7 @@ export function getOperations({
receipts,
abiMap,
rawPayload,
maxInputs,
}),
...getContractTransferOperations({ receipts }),
...getWithdrawFromFuelOperations({ inputs, receipts }),
Expand Down
1 change: 1 addition & 0 deletions packages/providers/src/transaction-summary/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export type InputOutputParam = InputParam & OutputParam;
export type GetOperationParams = {
transactionType: TransactionType;
abiMap?: AbiMap;
maxInputs: BN;
} & InputOutputParam &
ReceiptParam &
RawPayloadParam;
Expand Down

0 comments on commit ddf1bd2

Please sign in to comment.