Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions yarn-project/aztec.js/src/contract/deploy_sent_tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createLogger } from '@aztec/foundation/log';
import type { FieldsOf } from '@aztec/foundation/types';
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
import type { PXE } from '@aztec/stdlib/interfaces/client';
import type { AztecNode, PXE } from '@aztec/stdlib/interfaces/client';
import type { TxHash, TxReceipt } from '@aztec/stdlib/tx';

import type { Wallet } from '../account/index.js';
Expand All @@ -29,13 +29,13 @@ export class DeploySentTx<TContract extends Contract = Contract> extends SentTx
private log = createLogger('aztecjs:deploy_sent_tx');

constructor(
wallet: PXE | Wallet,
pxeOrWallet: PXE | Wallet,
txHashPromise: Promise<TxHash>,
private postDeployCtor: (address: AztecAddress, wallet: Wallet) => Promise<TContract>,
/** A getter for the deployed contract instance */
public instanceGetter: () => Promise<ContractInstanceWithAddress>,
) {
super(wallet, txHashPromise);
super(pxeOrWallet, txHashPromise);
}

/**
Expand All @@ -62,8 +62,9 @@ export class DeploySentTx<TContract extends Contract = Contract> extends SentTx
}

protected async getContractObject(wallet?: Wallet): Promise<TContract> {
const isWallet = (pxe: PXE | Wallet): pxe is Wallet => !!(pxe as Wallet).createTxExecutionRequest;
const contractWallet = wallet ?? (isWallet(this.pxe) && this.pxe);
const isWallet = (pxeOrWallet: PXE | Wallet | AztecNode): pxeOrWallet is Wallet =>
!!(pxeOrWallet as Wallet).createTxExecutionRequest;
const contractWallet = wallet ?? (isWallet(this.pxeOrNode) && this.pxeOrNode);
if (!contractWallet) {
throw new Error(`A wallet is required for creating a contract instance`);
}
Expand Down
34 changes: 30 additions & 4 deletions yarn-project/aztec.js/src/contract/sent_tx.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Fr } from '@aztec/foundation/fields';
import type { PXE } from '@aztec/stdlib/interfaces/client';
import type { AztecNode, PXE } from '@aztec/stdlib/interfaces/client';
import { TxHash, type TxReceipt, TxStatus } from '@aztec/stdlib/tx';

import { type MockProxy, mock } from 'jest-mock-extended';
Expand All @@ -8,21 +8,23 @@ import { SentTx } from './sent_tx.js';

describe('SentTx', () => {
let pxe: MockProxy<PXE>;
let node: MockProxy<AztecNode>;
let txHashPromise: Promise<TxHash>;

let sentTx: SentTx;

beforeEach(() => {
pxe = mock();
node = mock();
txHashPromise = Promise.resolve(new TxHash(new Fr(1n)));
sentTx = new SentTx(pxe, txHashPromise);
});

describe('wait', () => {
describe('wait with PXE', () => {
let txReceipt: TxReceipt;
beforeEach(() => {
txReceipt = { status: TxStatus.SUCCESS, blockNumber: 20 } as TxReceipt;
pxe.getTxReceipt.mockResolvedValue(txReceipt);
sentTx = new SentTx(pxe, txHashPromise);
});

it('throws if tx is dropped', async () => {
Expand All @@ -31,7 +33,7 @@ describe('SentTx', () => {
});

it('waits for the tx to be proven', async () => {
const waitOpts = { timeout: 1, interval: 0.4, waitForNotesAvailable: false, proven: true, provenTimeout: 2 };
const waitOpts = { timeout: 1, interval: 0.4, proven: true, provenTimeout: 2 };
pxe.getProvenBlockNumber.mockResolvedValue(10);
await expect(sentTx.wait(waitOpts)).rejects.toThrow(/timeout/i);

Expand All @@ -40,4 +42,28 @@ describe('SentTx', () => {
expect(actual).toEqual(txReceipt);
});
});

describe('wait with node', () => {
let txReceipt: TxReceipt;
beforeEach(() => {
txReceipt = { status: TxStatus.SUCCESS, blockNumber: 20 } as TxReceipt;
node.getTxReceipt.mockResolvedValue(txReceipt);
sentTx = new SentTx(node, txHashPromise);
});

it('throws if tx is dropped', async () => {
node.getTxReceipt.mockResolvedValue({ ...txReceipt, status: TxStatus.DROPPED } as TxReceipt);
await expect(sentTx.wait({ timeout: 1, interval: 0.4, ignoreDroppedReceiptsFor: 0 })).rejects.toThrow(/dropped/);
});

it('waits for the tx to be proven', async () => {
const waitOpts = { timeout: 1, interval: 0.4, proven: true, provenTimeout: 2 };
node.getProvenBlockNumber.mockResolvedValue(10);
await expect(sentTx.wait(waitOpts)).rejects.toThrow(/timeout/i);

node.getProvenBlockNumber.mockResolvedValue(20);
const actual = await sentTx.wait(waitOpts);
expect(actual).toEqual(txReceipt);
});
});
});
16 changes: 8 additions & 8 deletions yarn-project/aztec.js/src/contract/sent_tx.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { retryUntil } from '@aztec/foundation/retry';
import type { FieldsOf } from '@aztec/foundation/types';
import type { GetPublicLogsResponse, PXE } from '@aztec/stdlib/interfaces/client';
import type { AztecNode, GetPublicLogsResponse, PXE } from '@aztec/stdlib/interfaces/client';
import { type TxHash, type TxReceipt, TxStatus } from '@aztec/stdlib/tx';

/** Options related to waiting for a tx. */
Expand Down Expand Up @@ -30,11 +30,11 @@ export const DefaultWaitOpts: WaitOpts = {
};

/**
* The SentTx class represents a sent transaction through the PXE, providing methods to fetch
* The SentTx class represents a sent transaction through the PXE (or directly to a node) providing methods to fetch
* its hash, receipt, and mining status.
*/
export class SentTx {
constructor(protected pxe: PXE, protected txHashPromise: Promise<TxHash>) {}
constructor(protected pxeOrNode: PXE | AztecNode, protected txHashPromise: Promise<TxHash>) {}

/**
* Retrieves the transaction hash of the SentTx instance.
Expand All @@ -56,7 +56,7 @@ export class SentTx {
*/
public async getReceipt(): Promise<TxReceipt> {
const txHash = await this.getTxHash();
return await this.pxe.getTxReceipt(txHash);
return await this.pxeOrNode.getTxReceipt(txHash);
}

/**
Expand All @@ -76,7 +76,7 @@ export class SentTx {
}
if (opts?.debug) {
const txHash = await this.getTxHash();
const { data: tx } = (await this.pxe.getTxEffect(txHash))!;
const { data: tx } = (await this.pxeOrNode.getTxEffect(txHash))!;
receipt.debugInfo = {
noteHashes: tx.noteHashes,
nullifiers: tx.nullifiers,
Expand All @@ -94,7 +94,7 @@ export class SentTx {
*/
public async getPublicLogs(): Promise<GetPublicLogsResponse> {
await this.wait();
return this.pxe.getPublicLogs({ txHash: await this.getTxHash() });
return this.pxeOrNode.getPublicLogs({ txHash: await this.getTxHash() });
}

protected async waitForReceipt(opts?: WaitOpts): Promise<TxReceipt> {
Expand All @@ -104,7 +104,7 @@ export class SentTx {

return await retryUntil(
async () => {
const txReceipt = await this.pxe.getTxReceipt(txHash);
const txReceipt = await this.pxeOrNode.getTxReceipt(txHash);
// If receipt is not yet available, try again
if (txReceipt.status === TxStatus.PENDING) {
return undefined;
Expand All @@ -130,7 +130,7 @@ export class SentTx {
protected async waitForProven(minedBlock: number, opts?: WaitOpts) {
return await retryUntil(
async () => {
const provenBlock = await this.pxe.getProvenBlockNumber();
const provenBlock = await this.pxeOrNode.getProvenBlockNumber();
return provenBlock >= minedBlock ? provenBlock : undefined;
},
'isProven',
Expand Down