Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement wait() method for QiTx response #317

Merged
merged 3 commits into from
Oct 17, 2024
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
20 changes: 18 additions & 2 deletions src/providers/abstract-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import {
PollingEventSubscriber,
PollingOrphanSubscriber,
PollingTransactionSubscriber,
PollingQiTransactionSubscriber,
} from './subscriber-polling.js';
import { getNodeLocationFromZone, getZoneFromNodeLocation } from '../utils/shards.js';
import { fromShard } from '../constants/shards.js';
Expand Down Expand Up @@ -159,6 +160,12 @@ export type Subscription =
hash: string;
zone: Zone;
}
| {
type: 'qiTransaction';
tag: string;
hash: string;
zone: Zone;
}
| {
type: 'event';
tag: string;
Expand Down Expand Up @@ -311,9 +318,16 @@ async function getSubscription(_event: ProviderEvent, zone?: Zone): Promise<Subs
}

if (isHexString(_event, 32)) {
const eventBytes = getBytes(_event);
const ninthBit = (eventBytes[1] & 0x01) === 0x01;

const hash = _event.toLowerCase();
zone = toZone(hash.slice(0, 4));
return { type: 'transaction', tag: getTag('tx', { hash }), hash, zone };
if (ninthBit) {
return { type: 'qiTransaction', tag: getTag('Tx', { hash }), hash, zone };
} else {
return { type: 'transaction', tag: getTag('tx', { hash }), hash, zone };
}
}

if ((<any>_event).orphan) {
Expand Down Expand Up @@ -1055,7 +1069,7 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
// For QiTransaction, use fromProto() directly
return new QiTransactionResponse(tx, this);
} else {
throw new Error('Unknown transaction type');
throw new Error(`Unknown transaction type: ${tx.type}`);
}
} catch (error) {
console.error('Error in _wrapTransactionResponse:', error);
Expand Down Expand Up @@ -1889,6 +1903,8 @@ export class AbstractProvider<C = FetchRequest> implements Provider {
return new PollingEventSubscriber(this as AbstractProvider, sub.filter);
case 'transaction':
return new PollingTransactionSubscriber(this as AbstractProvider, sub.hash, sub.zone);
case 'qiTransaction':
return new PollingQiTransactionSubscriber(this as AbstractProvider, sub.hash, sub.zone);
case 'orphan':
return new PollingOrphanSubscriber(this as AbstractProvider, sub.filter, sub.zone);
}
Expand Down
48 changes: 48 additions & 0 deletions src/providers/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2412,6 +2412,54 @@ export class QiTransactionResponse implements QiTransactionLike, QiTransactionRe
return blockNumber - this.blockNumber + 1;
}

async wait(_confirms?: number, _timeout?: number): Promise<null | QiTransactionResponse> {
const confirms = _confirms == null ? 1 : _confirms;
const timeout = _timeout == null ? 0 : _timeout;

const tx = await this.provider.getTransaction(this.hash);

if (confirms === 0 && tx) {
return tx as QiTransactionResponse;
}

const waiter = new Promise((resolve, reject) => {
// List of things to cancel when we have a result (one way or the other)
const cancellers: Array<() => void> = [];
const cancel = () => {
cancellers.forEach((c) => c());
};

// Set up any timeout requested
if (timeout > 0) {
const timer = setTimeout(() => {
cancel();
reject(makeError('wait for transaction timeout', 'TIMEOUT'));
}, timeout);
cancellers.push(() => {
clearTimeout(timer);
});
}

const txListener = async (tx: QiTransactionResponse) => {
// Done; return it!
if ((await tx.confirmations()) >= confirms) {
cancel();
try {
resolve(tx);
} catch (error) {
reject(error);
}
}
};
cancellers.push(() => {
this.provider.off(this.hash, txListener);
});
this.provider.on(this.hash, txListener);
});

return await (<Promise<QiTransactionResponse>>waiter);
}

/**
* Returns `true` if this transaction has been included.
*
Expand Down
27 changes: 25 additions & 2 deletions src/providers/subscriber-polling.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { toZone, Zone } from '../constants/index.js';
import { toShard } from '../constants/shards.js';
import { assert, isHexString } from '../utils/index.js';
import { assert, getBytes, isHexString } from '../utils/index.js';
import { getZoneFromNodeLocation } from '../utils/shards.js';
import { getZoneFromEventFilter, type EventFilter, type OrphanFilter, type ProviderEvent } from './provider.js';

Expand Down Expand Up @@ -31,7 +31,14 @@ export function getPollingSubscriber(provider: AbstractProvider, event: Provider
}

if (isHexString(event, 32)) {
return new PollingTransactionSubscriber(provider, event, zone);
const eventBytes = getBytes(event);
const ninthBit = (eventBytes[1] & 0x01) === 0x01;

if (ninthBit) {
return new PollingQiTransactionSubscriber(provider, event, zone);
} else {
return new PollingTransactionSubscriber(provider, event, zone);
}
}

assert(false, 'unsupported polling event', 'UNSUPPORTED_OPERATION', {
Expand Down Expand Up @@ -321,6 +328,22 @@ export class PollingTransactionSubscriber extends OnBlockSubscriber {
}
}

export class PollingQiTransactionSubscriber extends OnBlockSubscriber {
#hash: string;

constructor(provider: AbstractProvider, hash: string, zone: Zone) {
super(provider, zone);
this.#hash = hash;
}

async _poll(blockNumber: number, provider: AbstractProvider): Promise<void> {
const tx = await provider.getTransaction(this.#hash);
if (tx && tx.isMined()) {
provider.emit(this.#hash, toZone(this.#hash.slice(0, 4)), tx);
}
}
}

/**
* A **PollingEventSubscriber** will poll for a given filter for its logs.
*
Expand Down
2 changes: 1 addition & 1 deletion src/transaction/qi-transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export class QiTransaction extends AbstractTransaction<string> implements QiTran

const prevTxHash = this.txInputs[0].txhash;
const prevTxHashBytes = getBytes(prevTxHash);
const origin = prevTxHashBytes[1]; // Get the second byte (0-based index)
const origin = prevTxHashBytes[2]; // Get the third byte (0-based index)
hashBuffer[0] = origin;
hashBuffer[1] |= 0x80;
hashBuffer[2] = origin;
Expand Down
Loading