Merge branch 'misc_updates' into 'development'
Make waitForTransaction part of BaseBlockchain See merge request GeneralProtocols/xo/stack!71
This commit is contained in:
@@ -35,11 +35,6 @@ publish:development:
|
|||||||
GITLAB_USER_EMAIL: 'ci@stack.xo.cash'
|
GITLAB_USER_EMAIL: 'ci@stack.xo.cash'
|
||||||
GITLAB_USER_NAME: 'GitLab CI'
|
GITLAB_USER_NAME: 'GitLab CI'
|
||||||
script:
|
script:
|
||||||
# Add a small delay to allow GitLab to fully process the merge
|
|
||||||
# NOTE: Temporary hack to check if publish is not working due to race condition.
|
|
||||||
- echo "Waiting 30 seconds for GitLab to process merge..."
|
|
||||||
- sleep 30
|
|
||||||
|
|
||||||
# Setup git config
|
# Setup git config
|
||||||
- git config --global user.email "${GITLAB_USER_EMAIL}"
|
- git config --global user.email "${GITLAB_USER_EMAIL}"
|
||||||
- git config --global user.name "${GITLAB_USER_NAME}"
|
- git config --global user.name "${GITLAB_USER_NAME}"
|
||||||
|
|||||||
@@ -184,24 +184,10 @@ export class Address {
|
|||||||
let payload = sha256.hash(bytes);
|
let payload = sha256.hash(bytes);
|
||||||
|
|
||||||
if (type === 'P2SH20') {
|
if (type === 'P2SH20') {
|
||||||
// Make sure length is 20 bytes.
|
|
||||||
if (bytes.length !== 20) {
|
|
||||||
throw new Error(
|
|
||||||
`Invalid payload length. Received '${bytes.length}', expected 20 for P2SH20`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// RIPEMD160 the SHA256 hash.
|
// RIPEMD160 the SHA256 hash.
|
||||||
payload = ripemd160.hash(payload);
|
payload = ripemd160.hash(payload);
|
||||||
} else if (type === 'P2SH32') {
|
} else if (type === 'P2SH32') {
|
||||||
// Make sure length is 32 bytes.
|
// SHA256 Hash the SHA256 hash a second time.
|
||||||
if (bytes.length !== 32) {
|
|
||||||
throw new Error(
|
|
||||||
`Invalid payload length. Received '${bytes.length}', expected 32 for P2SH20`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SHA256 Hash the SHA256 hash a seconr time.
|
|
||||||
payload = sha256.hash(payload);
|
payload = sha256.hash(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { Bytes } from './bytes.js';
|
import { Bytes } from './bytes.js';
|
||||||
|
|
||||||
import { assembleBytecodeBCH, disassembleBytecodeBCH } from '@bitauth/libauth';
|
import {
|
||||||
|
assembleBytecodeBCH,
|
||||||
|
disassembleBytecodeBCH,
|
||||||
|
compileCashAssembly,
|
||||||
|
} from '@bitauth/libauth';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Script Entity.
|
* Script Entity.
|
||||||
@@ -109,6 +113,21 @@ export class Script {
|
|||||||
return new this(assembleResult.bytecode);
|
return new this(assembleResult.bytecode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: In its current form, this is pretty useless because it does not allow OP_CODES.
|
||||||
|
// Disabling because it will probably just cause confusion.
|
||||||
|
/*
|
||||||
|
public static fromCashASM(cashASM: string) {
|
||||||
|
const result = compileCashAssembly(cashASM);
|
||||||
|
|
||||||
|
if (typeof result === 'string') {
|
||||||
|
// TODO: Make error more detailed.
|
||||||
|
throw new Error(`Failed to parse CashASM: ${result}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new this(result);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Script Entity from the given bytes (as hexadecimal string).
|
* Create a Script Entity from the given bytes (as hexadecimal string).
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
type BlockchainTransactions,
|
type BlockchainTransactions,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
|
|
||||||
import { type Transaction } from '@xocash/primitives';
|
import { Transaction } from '@xocash/primitives';
|
||||||
|
|
||||||
export type BlockchainEvents = {
|
export type BlockchainEvents = {
|
||||||
isConnectedUpdated: boolean;
|
isConnectedUpdated: boolean;
|
||||||
@@ -177,4 +177,55 @@ export abstract class BaseBlockchain<
|
|||||||
transactionHash: string,
|
transactionHash: string,
|
||||||
callback: BlockchainCallback<TransactionNotificationPayload>,
|
callback: BlockchainCallback<TransactionNotificationPayload>,
|
||||||
): Promise<boolean>;
|
): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for a transaction to be seen by the node.
|
||||||
|
*
|
||||||
|
* @param tx - The transaction to wait for. Can be a Uint8Array, Transaction instance, or a string.
|
||||||
|
* @param timeoutMs - The maximum time to wait in milliseconds before timing out. Defaults to 10,000ms (10 seconds).
|
||||||
|
* @returns A Promise that resolves when the transaction is seen by the node or rejects if the timeout is reached.
|
||||||
|
* @throws Error if the transaction is not seen by the node within the specified timeout.
|
||||||
|
*/
|
||||||
|
async waitForTransaction(
|
||||||
|
tx: Uint8Array | Transaction | string,
|
||||||
|
timeoutMs = 10_000,
|
||||||
|
) {
|
||||||
|
// Cast the transaction.
|
||||||
|
if (!(tx instanceof Transaction)) {
|
||||||
|
tx = Transaction.from(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const txHash = tx.toHashHex();
|
||||||
|
|
||||||
|
// First, subscribe to the transaction
|
||||||
|
let unsubscribeCallback: () => void;
|
||||||
|
const subscriptionPromise = this.subscribeTransaction(txHash, () => {
|
||||||
|
if (unsubscribeCallback) {
|
||||||
|
unsubscribeCallback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Then create the wait promise without an async executor
|
||||||
|
const waitForTxPromise = new Promise<void>((resolve, reject) => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
if (unsubscribeCallback) {
|
||||||
|
unsubscribeCallback();
|
||||||
|
}
|
||||||
|
reject(new Error(`Failed to broadcast ${txHash}`));
|
||||||
|
}, timeoutMs);
|
||||||
|
|
||||||
|
// Create a subscribe function so that we get notified when transaction is seen by network
|
||||||
|
unsubscribeCallback = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
this.unsubscribeTransaction(txHash, unsubscribeCallback);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for subscription to be set up first
|
||||||
|
await subscriptionPromise;
|
||||||
|
|
||||||
|
// Then wait for either resolution or timeout
|
||||||
|
return waitForTxPromise;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -317,40 +317,6 @@ export class BlockchainElectrum extends BaseBlockchain<
|
|||||||
return transactionsIndexed;
|
return transactionsIndexed;
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForTransaction(
|
|
||||||
tx: Uint8Array | Transaction | string,
|
|
||||||
timeoutMs = 10_000,
|
|
||||||
) {
|
|
||||||
// Cast the transaction.
|
|
||||||
if (!(tx instanceof Transaction)) {
|
|
||||||
tx = Transaction.from(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to broadcast the transaction.
|
|
||||||
const waitForTxPromise = new Promise<void>(async (resolve, reject) => {
|
|
||||||
// Set a timeout.
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
reject(new Error(`Failed to broadcast ${tx.toHashHex()}`));
|
|
||||||
}, timeoutMs);
|
|
||||||
|
|
||||||
// Create a subscribe function so that we get notified when transaction is seen by network
|
|
||||||
const subscribeCallback = () => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
this.unsubscribeTransaction(tx.toHashHex(), subscribeCallback);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Subscribe to the transaction.
|
|
||||||
await this.subscribeTransaction(tx.toHashHex(), subscribeCallback);
|
|
||||||
});
|
|
||||||
|
|
||||||
return waitForTxPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Split out the "waitUntilSeen" into own function.
|
|
||||||
// This'll be useful for protocols like BIP70/JPP/CashConnect, etc.
|
|
||||||
// Also consider a fail callback:
|
|
||||||
// If a "waitFor" fails, we probably want to invalidate the tx by sending those inputs elsewhere.
|
|
||||||
async broadcastTransaction(
|
async broadcastTransaction(
|
||||||
tx: Transaction | Uint8Array | string,
|
tx: Transaction | Uint8Array | string,
|
||||||
opts: BroadcastOpts = { timeoutMs: 10_000, waitUntilSeen: true },
|
opts: BroadcastOpts = { timeoutMs: 10_000, waitUntilSeen: true },
|
||||||
|
|||||||
Reference in New Issue
Block a user