var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { createClient } from "../blockchainClient/blockchainClient";
import { calculateBlockRID, composeProofTransactionObject, fetchAndVerifyTransaction, getAnchoringTransactionForBlockRid, getClusterInfo, getClusterOfBlockchain, } from "./utils";
import { toString, toBuffer } from "../formatter";
import { BlockAnchoringException, ConfirmationProofException } from "./error";
/**
 * Creates an ICCF (Inter-Chain Communication Framework) proof transaction.
 * This function generates a proof that a specific transaction has occurred on the source blockchain
 * and constructs an ICCF proof transaction that can be posted to the target blockchain.
 *
 * @param {IClient} client - The client configured to communicate with the management chain.
 * @param {Buffer} txToProveRid - The RID of the transaction to be proven.
 * @param {Buffer} txToProveHash - The hash of the transaction to be proven.
 * @param {PubKey[]} txToProveSigners - An array of public keys representing signers of the transaction to be proven.
 * @param {string} sourceBlockchainRid - The RID of the source blockchain.
 * @param {string} targetBlockchainRid - The RID of the target blockchain.
 * @param {PubKey[]} iccfTxSigners - An array of public keys representing signers of the ICCF proof transaction (optional, default: []).
 * @param {boolean} forceIntraNetworkIccfOperation - Whether to force the ICCF operation to be performed within the same network (optional, default: false).
 * @returns {Promise<IccfProof>} A promise that resolves to an ICCF proof object containing the ICCF proof transaction.
 */
export function createIccfProofTx(client, txToProveRid, txToProveHash, txToProveSigners, sourceBlockchainRid, targetBlockchainRid, iccfTxSigners = [], forceIntraNetworkIccfOperation = false) {
    return __awaiter(this, void 0, void 0, function* () {
        const clientConfiguredToSource = yield createClient({
            directoryNodeUrlPool: client.config.endpointPool.slice(),
            blockchainRid: sourceBlockchainRid,
        });
        const txProof = yield clientConfiguredToSource.getConfirmationProof(txToProveRid);
        if (!txProof || !txProof.hash) {
            throw new ConfirmationProofException(txToProveRid);
        }
        const proofHash = txProof.hash;
        const { verifiedTx, verifiedTxHash } = !txToProveHash.equals(proofHash)
            ? yield fetchAndVerifyTransaction(clientConfiguredToSource, txToProveRid, proofHash, txToProveSigners)
            : { verifiedTx: null, verifiedTxHash: txToProveHash };
        const sourceCluster = yield getClusterOfBlockchain(client, toBuffer(sourceBlockchainRid));
        const targetCluster = yield getClusterOfBlockchain(client, toBuffer(targetBlockchainRid));
        if (!forceIntraNetworkIccfOperation && sourceCluster === targetCluster) {
            // intra-cluster
            const intraClusterProofTx = composeProofTransactionObject(sourceBlockchainRid, verifiedTxHash, txProof, iccfTxSigners, undefined, undefined, false);
            return { iccfTx: intraClusterProofTx };
        }
        else {
            // intra-network
            const anchoringClient = yield getAnchoringClient(client, sourceBlockchainRid, sourceCluster);
            const anchoringTx = yield getBlockAnchoringTransaction(clientConfiguredToSource, anchoringClient, undefined, txProof);
            const anchoringProof = yield anchoringClient.getConfirmationProof(anchoringTx.txRid);
            const intraNetworkProofTx = composeProofTransactionObject(sourceBlockchainRid, verifiedTxHash, txProof, iccfTxSigners, anchoringTx, anchoringProof);
            return { iccfTx: intraNetworkProofTx, verifiedTx };
        }
    });
}
/**
 * Checks whether a given transaction is included in the cluster anchoring chain and returns the
 * block anchoring transaction. If `txProof` is not provided, it fetches the confirmation proof
 * using the `sourceClient`.
 *
 * @param sourceClient - A client configured to the blockchain where the trasnaction were made.
 * @param anchoringClient - The client responsible for querying the anchoring blockchain.
 * @param txRid - The transaction RID to check for anchoring.
 * @param txProof - (Optional) The transaction proof for the specified `txRid`.
 * @returns A Promise that resolves to the anchored transaction response object.
 */
export function getBlockAnchoringTransaction(sourceClient, anchoringClient, txRid, txProof) {
    return __awaiter(this, void 0, void 0, function* () {
        if (!(txRid || txProof)) {
            throw Error("Missing a txRid or TxProof");
        }
        const confirmationProof = txProof !== null && txProof !== void 0 ? txProof : (yield sourceClient.getConfirmationProof(txRid));
        if (!confirmationProof) {
            return null;
        }
        const blockRid = calculateBlockRID(confirmationProof);
        const blockchainRid = sourceClient.config.blockchainRid;
        const anchoringTxResponse = yield getAnchoringTransactionForBlockRid(anchoringClient, toBuffer(blockchainRid), blockRid);
        if (!anchoringTxResponse) {
            throw new BlockAnchoringException();
        }
        return anchoringTxResponse;
    });
}
/**
 * Checks whether a given transaction is included in the anchoring blockchain.
 *
 * @param sourceClient - A client configured to the blockchain where the trasnaction were made.
 * @param anchoringClient - The client responsible for querying the anchoring blockchain.
 * @param txRid - The transaction RID to check for anchoring.
 * @param txProof - (Optional) The transaction proof for the specified `txRid`.
 * @returns A Promise that resolves to `true` if the transaction is anchored, `false` otherwise.
 */
export function isBlockAnchored(sourceClient, anchoringClient, txRid, txProof) {
    return __awaiter(this, void 0, void 0, function* () {
        return !!(yield getBlockAnchoringTransaction(sourceClient, anchoringClient, txRid, txProof));
    });
}
/**
 * Gets a client configured for the cluster anchoring blockchain of a cluster. Takes a specific
 * cluster name or blockchain RID to determine the cluster.
 * @param client - The client configured to communicate with the management chain.
 * @param dappBlockchainRid - (Optional) The RID of a blockchain which anchoring wants to be checked.
 * @param cluster - (Optional) The cluster of interest.
 * @returns A Promise that resolves to the client configured to a cluster anchoring chain.
 */
export function getAnchoringClient(client, dappBlockchainRid, cluster) {
    return __awaiter(this, void 0, void 0, function* () {
        if (!(dappBlockchainRid || cluster)) {
            throw Error("Missing a dapp blockchainRid or cluster name");
        }
        const sourceCluster = cluster !== null && cluster !== void 0 ? cluster : (yield getClusterOfBlockchain(client, toBuffer(dappBlockchainRid)));
        if (!sourceCluster) {
            throw Error("No cluster could be found");
        }
        const sourceClusterInfo = yield getClusterInfo(client, sourceCluster);
        if (!sourceClusterInfo || !sourceClusterInfo.anchoring_chain) {
            throw Error("Cluster info could not be found");
        }
        const clientConfiguredToAnchoringchain = yield createClient({
            directoryNodeUrlPool: client.config.endpointPool.slice(),
            blockchainRid: toString(sourceClusterInfo.anchoring_chain),
        });
        return clientConfiguredToAnchoringchain;
    });
}
//# sourceMappingURL=IccfProofTxMaterialBuilder.js.map