Skip to content

Commit

Permalink
feature: Added calltable serialization for TransactionV1, Changing Tr…
Browse files Browse the repository at this point in the history
…ansactionV1 structure
  • Loading branch information
alexmyshchyshyn committed Nov 21, 2024
1 parent 829463f commit 332a002
Show file tree
Hide file tree
Showing 14 changed files with 641 additions and 861 deletions.
5 changes: 5 additions & 0 deletions src/types/ByteConverters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ export const toBytesNumber = (bitSize: number, signed: boolean) => (
*/
export const toBytesU8 = toBytesNumber(8, false);

/**
* Converts an 16-bit unsigned integer (`u16`) to little-endian byte format.
*/
export const toBytesU16 = toBytesNumber(16, false);

/**
* Converts a 32-bit signed integer (`i32`) to little-endian byte format.
*/
Expand Down
66 changes: 66 additions & 0 deletions src/types/CalltableSerialization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { concat } from '@ethersproject/bytes';
import { toBytesU16, toBytesU32 } from './ByteConverters';

export class Field {
readonly index: number;
readonly offset: number;
readonly value: Uint8Array;

constructor(index: number, offset: number, value: Uint8Array) {
this.index = index;
this.offset = offset;
this.value = value;
}

/**
* Calculates the serialized vector size for the given number of fields.
* @returns The size of the serialized vector.
*/
static serializedVecSize(): number {
return 4 + 4 * 2;
}
}

export class CalltableSerialization {
private fields: Field[] = [];
private currentOffset = 0;

/**
* Adds a field to the call table.
* @param index The field index.
* @param value The field value as a byte array.
* @returns The current instance of CalltableSerialization.
*/
addField(index: number, value: Uint8Array): CalltableSerialization {
if (this.fields.length !== index) {
throw new Error('Add fields in correct index order.');
}

const field = new Field(index, this.currentOffset, value);
this.fields.push(field);
this.currentOffset += value.length;

return this;
}

/**
* Serializes the call table to a byte array.
* @returns A Uint8Array representing the serialized call table.
*/
toBytes(): Uint8Array {
const calltableBytes: Uint8Array[] = [];
const payloadBytes: Uint8Array[] = [];

calltableBytes.push(toBytesU32(this.fields.length));

for (const field of this.fields) {
calltableBytes.push(toBytesU16(field.index));
calltableBytes.push(toBytesU32(field.offset));
payloadBytes.push(field.value);
}

calltableBytes.push(toBytesU32(this.currentOffset));

return concat([...calltableBytes, ...payloadBytes]);
}
}
4 changes: 2 additions & 2 deletions src/types/Deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from './Transaction';
import { TransactionEntryPoint } from './TransactionEntryPoint';
import { InitiatorAddr } from './InitiatorAddr';
import { ClassicMode, PricingMode } from './PricingMode';
import { PaymentLimitedMode, PricingMode } from './PricingMode';
import { TransactionTarget } from './TransactionTarget';
import { TransactionScheduling } from './TransactionScheduling';
import { ExecutableDeployItem } from './ExecutableDeployItem';
Expand Down Expand Up @@ -394,7 +394,7 @@ export class Deploy {
const standardPayment = paymentAmount === 0 && !deploy.payment.moduleBytes;

const pricingMode = new PricingMode();
const classicMode = new ClassicMode();
const classicMode = new PaymentLimitedMode();
classicMode.gasPriceTolerance = 1;
classicMode.paymentAmount = paymentAmount;
classicMode.standardPayment = standardPayment;
Expand Down
49 changes: 23 additions & 26 deletions src/types/ExecutableDeployItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@ import { concat } from '@ethersproject/bytes';
import { Args } from './Args';
import {
CLValue,
CLValueByteArray,
CLValueOption,
CLValueString,
CLValueUInt32,
CLValueUInt512,
CLValueUInt64
} from './clvalue';
import { ContractHash, URef } from './key';
import { deserializeArgs, serializeArgs } from './SerializationUtils';
import {
byteArrayJsonDeserializer,
byteArrayJsonSerializer,
deserializeArgs,
serializeArgs
} from './SerializationUtils';
import { PublicKey } from './keypair';
import { Conversions } from './Conversions';
import { toBytesArrayU8 } from './ByteConverters';

/**
* Enum representing the different types of executable deploy items.
Expand All @@ -37,8 +41,13 @@ export class ModuleBytes {
/**
* The module bytes in hexadecimal format.
*/
@jsonMember({ name: 'module_bytes', constructor: String })
moduleBytes!: string;
@jsonMember({
name: 'module_bytes',
constructor: Uint8Array,
serializer: byteArrayJsonSerializer,
deserializer: byteArrayJsonDeserializer
})
moduleBytes: Uint8Array;

/**
* The arguments passed to the module.
Expand All @@ -54,7 +63,7 @@ export class ModuleBytes {
* @param moduleBytes The module bytes in hexadecimal format.
* @param args The arguments for the module.
*/
constructor(moduleBytes: string, args: Args) {
constructor(moduleBytes: Uint8Array, args: Args) {
this.moduleBytes = moduleBytes;
this.args = args;
}
Expand All @@ -64,22 +73,13 @@ export class ModuleBytes {
* @returns The serialized byte array.
*/
bytes(): Uint8Array {
const moduleBytes = new Uint8Array(Buffer.from(this.moduleBytes, 'hex'));
const lengthBytes = CLValueUInt32.newCLUInt32(
BigNumber.from(moduleBytes.length)
).bytes();
const bytesArrayBytes = CLValueByteArray.newCLByteArray(
moduleBytes
).bytes();
if (!this.args) throw new Error('Missing arguments for ModuleBytes');

let result = concat([lengthBytes, bytesArrayBytes]);

if (this.args) {
const argBytes = this.args.toBytes();
result = concat([result, argBytes]);
}

return result;
return concat([
Uint8Array.from([0]),
toBytesArrayU8(this.moduleBytes),
this.args.toBytes()
]);
}
}

Expand Down Expand Up @@ -541,7 +541,7 @@ export class ExecutableDeployItem {
): ExecutableDeployItem {
const executableDeployItem = new ExecutableDeployItem();
executableDeployItem.moduleBytes = new ModuleBytes(
'',
Uint8Array.from([]),
Args.fromMap({ amount: CLValueUInt512.newCLUInt512(amount) })
);
return executableDeployItem;
Expand Down Expand Up @@ -614,10 +614,7 @@ export class ExecutableDeployItem {
args: Args
): ExecutableDeployItem {
const executableDeployItem = new ExecutableDeployItem();
executableDeployItem.moduleBytes = new ModuleBytes(
Conversions.encodeBase16(moduleBytes),
args
);
executableDeployItem.moduleBytes = new ModuleBytes(moduleBytes, args);

return executableDeployItem;
}
Expand Down
25 changes: 14 additions & 11 deletions src/types/InitiatorAddr.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { jsonObject, jsonMember } from 'typedjson';
import { concat } from '@ethersproject/bytes';

import { PublicKey } from './keypair';
import { AccountHash } from './key';
import { CalltableSerialization } from './CalltableSerialization';

/**
* Represents an address for an initiator, which can either be a public key or an account hash.
Expand Down Expand Up @@ -45,20 +45,23 @@ export class InitiatorAddr {
* @returns A `Uint8Array` representing the initiator address.
*/
public toBytes(): Uint8Array {
let result: Uint8Array;

if (this.accountHash) {
const prefix = new Uint8Array([1]);
result = concat([prefix, this.accountHash.toBytes()]);
const calltableSerialization = new CalltableSerialization();

calltableSerialization.addField(0, Uint8Array.of(1));
calltableSerialization.addField(1, this.accountHash.toBytes());

return calltableSerialization.toBytes();
} else if (this.publicKey) {
const prefix = new Uint8Array([0]);
const publicKeyBytes = this.publicKey.bytes() || new Uint8Array(0);
result = concat([prefix, publicKeyBytes]);
} else {
result = new Uint8Array(0);
const calltableSerialization = new CalltableSerialization();

calltableSerialization.addField(0, Uint8Array.of(0));
calltableSerialization.addField(1, this.publicKey.bytes());

return calltableSerialization.toBytes();
}

return result;
throw new Error('Unable to serialize InitiatorAddr');
}

/**
Expand Down
Loading

0 comments on commit 332a002

Please sign in to comment.