Skip to content

Commit

Permalink
Merge branch 'master' into st/chore/revert-add-sign-transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
Torres-ssf authored Sep 11, 2024
2 parents a8a4f5d + 99d39e9 commit 6ab887c
Show file tree
Hide file tree
Showing 18 changed files with 849 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .changeset/afraid-starfishes-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuel-ts/transactions": patch
"@fuel-ts/account": patch
---

feat: introduce upload and upgrade transaction request
2 changes: 2 additions & 0 deletions packages/account/src/providers/transaction-request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export * from './transaction-request';
export * from './blob-transaction-request';
export * from './create-transaction-request';
export * from './script-transaction-request';
export * from './upgrade-transaction-request';
export * from './upload-transaction-request';
export * from './errors';
export * from './scripts';
export * from './types';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Address } from '@fuel-ts/address';
import { ZeroBytes32 } from '@fuel-ts/address/configs';
import { randomBytes } from '@fuel-ts/crypto';
import { bn, toNumber } from '@fuel-ts/math';
import { TransactionType } from '@fuel-ts/transactions';
import { TransactionType, UpgradePurposeTypeEnum } from '@fuel-ts/transactions';
import { concat, hexlify } from '@fuel-ts/utils';
import { ASSET_A, ASSET_B } from '@fuel-ts/utils/test-utils';

Expand All @@ -14,6 +14,8 @@ import Provider from '../provider';
import type { CoinTransactionRequestInput } from './input';
import { ScriptTransactionRequest } from './script-transaction-request';
import type { TransactionRequestLike } from './types';
import type { UpgradeTransactionRequest } from './upgrade-transaction-request';
import type { UploadTransactionRequest } from './upload-transaction-request';
import { transactionRequestify } from './utils';

/**
Expand Down Expand Up @@ -248,4 +250,45 @@ describe('transactionRequestify', () => {
expect(txRequest.outputs).toEqual(txRequestLike.outputs);
expect(txRequest.witnesses).toEqual(txRequestLike.witnesses);
});

it('should keep data from input in transaction request created [upgrade]', () => {
const txRequestLike: TransactionRequestLike = {
type: TransactionType.Upgrade,
inputs: [],
outputs: [],
bytecodeWitnessIndex: 0,
upgradePurpose: {
type: UpgradePurposeTypeEnum.ConsensusParameters,
checksum: ZeroBytes32,
},
};

const txRequest = transactionRequestify(txRequestLike) as UpgradeTransactionRequest;

expect(txRequest.upgradePurpose).toEqual(txRequestLike.upgradePurpose);
expect(txRequest.bytecodeWitnessIndex).toEqual(txRequestLike.bytecodeWitnessIndex);
expect(txRequest.upgradePurpose.type).toEqual(txRequestLike.upgradePurpose?.type);
expect(txRequest.type).toEqual(txRequestLike.type);
});

it('should keep data from input in transaction request created [upload]', () => {
const txRequestLike: TransactionRequestLike = {
type: TransactionType.Upload,
inputs: [],
outputs: [],
witnessIndex: 0,
subsection: {
root: ZeroBytes32,
subsectionIndex: 0,
subsectionsNumber: 1,
proofSet: [],
},
};

const txRequest = transactionRequestify(txRequestLike) as UploadTransactionRequest;

expect(txRequest.subsection).toEqual(txRequestLike.subsection);
expect(txRequest.witnessIndex).toEqual(txRequestLike.witnessIndex);
expect(txRequest.type).toEqual(txRequestLike.type);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import type {
Policy,
TransactionCreate,
TransactionBlob,
TransactionUpload,
TransactionUpgrade,
} from '@fuel-ts/transactions';
import {
PolicyType,
Expand Down Expand Up @@ -193,7 +195,12 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi
};
}

abstract toTransaction(): TransactionCreate | TransactionScript | TransactionBlob;
abstract toTransaction():
| TransactionCreate
| TransactionScript
| TransactionBlob
| TransactionUpgrade
| TransactionUpload;

/**
* Converts the transaction request to a byte array.
Expand Down
16 changes: 14 additions & 2 deletions packages/account/src/providers/transaction-request/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,27 @@ import type {
ScriptTransactionRequest,
ScriptTransactionRequestLike,
} from './script-transaction-request';
import type {
UpgradeTransactionRequest,
UpgradeTransactionRequestLike,
} from './upgrade-transaction-request';
import type {
UploadTransactionRequest,
UploadTransactionRequestLike,
} from './upload-transaction-request';

export type TransactionRequest =
| ScriptTransactionRequest
| CreateTransactionRequest
| BlobTransactionRequest;
| BlobTransactionRequest
| UpgradeTransactionRequest
| UploadTransactionRequest;
export type TransactionRequestLike =
| ({ type: TransactionType.Script } & ScriptTransactionRequestLike)
| ({ type: TransactionType.Create } & CreateTransactionRequestLike)
| ({ type: TransactionType.Blob } & BlobTransactionRequestLike);
| ({ type: TransactionType.Blob } & BlobTransactionRequestLike)
| ({ type: TransactionType.Upgrade } & UpgradeTransactionRequestLike)
| ({ type: TransactionType.Upload } & UploadTransactionRequestLike);

export type JsonAbisFromAllCalls = {
main: JsonAbi;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
import { FuelError } from '@fuel-ts/errors';
import { hash } from '@fuel-ts/hasher';
import type { BytesLike } from '@fuel-ts/interfaces';
import type { BN } from '@fuel-ts/math';
import {
TransactionType,
type TransactionUpgrade,
type UpgradePurpose,
UpgradePurposeTypeEnum,
} from '@fuel-ts/transactions';
import { hexlify } from '@fuel-ts/utils';
import { clone } from 'ramda';

import type { GasCosts } from '../provider';
import { calculateMetadataGasForTxUpgrade } from '../utils';

import { hashTransaction } from './hash-transaction';
import { BaseTransactionRequest, type BaseTransactionRequestLike } from './transaction-request';

/**
* @hidden
*/
export type UpgradePurposeRequest =
| {
type: UpgradePurposeTypeEnum.ConsensusParameters;
checksum: string;
}
| {
type: UpgradePurposeTypeEnum.StateTransition;
data: BytesLike;
};

/**
* @hidden
*/
export interface UpgradeTransactionRequestLike extends BaseTransactionRequestLike {
/** The upgrade purpose */
upgradePurpose?: UpgradePurposeRequest;

/** Witness index */
bytecodeWitnessIndex?: number;
}

export class UpgradeTransactionRequest extends BaseTransactionRequest {
static from(obj: UpgradeTransactionRequestLike) {
if (obj instanceof UpgradeTransactionRequest) {
return obj;
}
return new this(clone(obj));
}

/** The type of transaction */
type = TransactionType.Upgrade as const;
/** The upgrade purpose */
upgradePurpose: UpgradePurposeRequest;
/** Witness index of consensus */
bytecodeWitnessIndex: number;

/**
* Creates an instance `UpgradeTransactionRequest`.
*
* @param upgradeTransactionRequestLike - The initial values for the instance
*/
constructor({
upgradePurpose,
bytecodeWitnessIndex,
...rest
}: UpgradeTransactionRequestLike = {}) {
super(rest);
this.bytecodeWitnessIndex = bytecodeWitnessIndex ?? 0;
this.upgradePurpose = upgradePurpose ?? {
type: UpgradePurposeTypeEnum.ConsensusParameters,
checksum: '0x',
};
}

/**
* Adds a consensus parameters upgrade purpose.
*
* @param consensus - The consensus bytecode.
*
* @returns - The current instance of `UpgradeTransactionRequest`.
*/
addConsensusParametersUpgradePurpose(consensus: BytesLike) {
this.bytecodeWitnessIndex = this.addWitness(consensus);
this.upgradePurpose = {
type: UpgradePurposeTypeEnum.ConsensusParameters,
checksum: hash(consensus),
};
return this;
}

/**
* Adds a state transition upgrade purpose.
*
* @param bytecodeRoot - The Merkle root of the state transition.
*
* @returns - The current instance of `UpgradeTransactionRequest`.
*/
addStateTransitionUpgradePurpose(bytecodeRoot: BytesLike) {
this.upgradePurpose = {
type: UpgradePurposeTypeEnum.StateTransition,
data: hexlify(bytecodeRoot),
};
return this;
}

/**
* Adds an upgrade purpose.
*
* @param type - The upgrade purpose type.
* @param data - The bytecode or merkle root of upgrade purpose
*
* @returns - The current instance of `UpgradeTransactionRequest`.
*/
addUpgradePurpose(type: UpgradePurposeTypeEnum, data: BytesLike) {
if (type === UpgradePurposeTypeEnum.ConsensusParameters) {
this.addConsensusParametersUpgradePurpose(data);
}

if (type === UpgradePurposeTypeEnum.StateTransition) {
this.addStateTransitionUpgradePurpose(data);
}

return this;
}

/**
* Converts the transaction request to a `TransactionUpgrade`.
*
* @returns The transaction create object.
*/
toTransaction(): TransactionUpgrade {
let upgradePurpose: UpgradePurpose;

if (this.upgradePurpose.type === UpgradePurposeTypeEnum.ConsensusParameters) {
upgradePurpose = {
type: UpgradePurposeTypeEnum.ConsensusParameters,
data: {
witnessIndex: this.bytecodeWitnessIndex,
checksum: this.upgradePurpose.checksum,
},
};
} else if (this.upgradePurpose.type === UpgradePurposeTypeEnum.StateTransition) {
upgradePurpose = {
type: UpgradePurposeTypeEnum.StateTransition,
data: {
bytecodeRoot: hexlify(this.upgradePurpose.data),
},
};
} else {
throw new FuelError(FuelError.CODES.NOT_IMPLEMENTED, 'Invalid upgrade purpose');
}

return {
type: TransactionType.Upgrade,
...super.getBaseTransaction(),
upgradePurpose,
};
}

/**
* Gets the Transaction ID by hashing the transaction
*
* @param chainId - The chain ID.
*
* @returns - A hash of the transaction, which is the transaction ID.
*/
getTransactionId(chainId: number): string {
return hashTransaction(this, chainId);
}

/**
* Calculates the metadata gas cost for an upgrade transaction.
*
* @param gasCosts - gas costs passed from the chain.
*
* @returns metadata gas cost for the upgrade transaction.
*/
metadataGas(gasCosts: GasCosts): BN {
const txBytesSize = this.byteSize();

if (this.upgradePurpose.type === UpgradePurposeTypeEnum.ConsensusParameters) {
const witnessIndex = this.bytecodeWitnessIndex;
const consensusSize = this.witnesses[witnessIndex].length;
return calculateMetadataGasForTxUpgrade({
gasCosts,
txBytesSize,
consensusSize,
});
}

if (this.upgradePurpose.type === UpgradePurposeTypeEnum.StateTransition) {
return calculateMetadataGasForTxUpgrade({
gasCosts,
txBytesSize,
});
}

throw new FuelError(FuelError.CODES.NOT_IMPLEMENTED, 'Invalid upgrade purpose');
}
}
Loading

0 comments on commit 6ab887c

Please sign in to comment.