UNPKG

postchain-client

Version:

Client library for accessing a Postchain node through REST.

216 lines 13 kB
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 { DifferentNumberOfSignersException, MissingTransactionProof, ProofRidException, SignatureException, SystemChainException, } from "../../../src/ICCF/error"; import { calculateBlockRID, fetchAndVerifyTransaction, getAnchoringTransactionForBlockRid, getClusterOfBlockchain, } from "../../../src/ICCF/utils"; import { ensureString, toBuffer } from "../../../src/formatter"; import { gtvHash } from "../../../src/gtv"; import { encodeValue, encodeValueGtx } from "../../../src/gtx/serialization"; import { getDigestToSign, gtxToRawGtx, sign } from "../../../src/gtx/gtx"; import { makeKeyPair } from "../../../src/encryption/encryption"; import { createHeaderArray, getTestsClient } from "../../common/setups"; import { HttpResponse, http } from "msw"; import { server } from "../../../mocks/servers"; import { contentTypes, LOCAL_POOL, mockBufferBlockchainRid, mockStringBlockchainRid, mockThirtyTwoBytesBuffer, } from "../../common/mocks"; import { MERKLE_HASH_VERSIONS } from "../../../src/utils/constants"; import { UnexpectedStatusError } from "../../../src/blockchainClient/errors"; function encodeGtxToBuffer(gtx) { return encodeValueGtx(gtxToRawGtx(gtx)); } function createGtxObject(keypairs, op) { return __awaiter(this, void 0, void 0, function* () { let gtx = { blockchainRid: toBuffer("fcd29927aa06e75547036c8860633af2d8df8ff6c78f947a2d7c816cb13dc201"), operations: op === undefined ? [ { opName: "setInteger", args: ["126d2"], }, ] : op, signers: keypairs.map(key => key.pubKey), signatures: [], }; keypairs.forEach((key) => __awaiter(this, void 0, void 0, function* () { gtx = yield sign(gtx, key.privKey, 1, key.pubKey); })); return gtx; }); } const privkeyA = toBuffer("0101010101010101010101010101010101010101010101010101010101010101"); const keypairA = makeKeyPair(privkeyA); const privkeyB = toBuffer("2222222222222222222222222222222222222222222222222222222222222222"); const keypairB = makeKeyPair(privkeyB); let client; describe("ICCF tests", () => { beforeEach(() => __awaiter(void 0, void 0, void 0, function* () { server.listen(); client = yield getTestsClient({ failOverConfig: { attemptInterval: 100 }, }); })); afterEach(() => { server.resetHandlers(); }); const mockTransactionRequest = (rid, gtxResponseTx) => { server.use(http.get(`${LOCAL_POOL}/tx/${client.config.blockchainRid}/${rid.toString("hex")}`, () => { return HttpResponse.json({ tx: encodeGtxToBuffer(gtxResponseTx).toString("hex").toUpperCase(), }); })); }; const mockTransactionErrorOnRequest = (rid, error) => { server.use(http.get(`${LOCAL_POOL}/tx/${client.config.blockchainRid}/${ensureString(rid)}`, () => { return new HttpResponse(error, { status: 404, }); })); }; describe("fetchAndVerifyTransaction", () => { it("should fetch and verify transaction", () => __awaiter(void 0, void 0, void 0, function* () { const gtxResponseTx = yield createGtxObject([keypairA]); const rid = getDigestToSign(gtxResponseTx, 1); const txProofHash = gtvHash(gtxToRawGtx(gtxResponseTx), 1); mockTransactionRequest(rid, gtxResponseTx); const { verifiedTxHash } = yield fetchAndVerifyTransaction(client, rid, txProofHash, [ keypairA.pubKey, ]); expect(verifiedTxHash).toEqual(txProofHash); })); it("throws error if fetched tx hash does not match proof hash", () => __awaiter(void 0, void 0, void 0, function* () { const gtxResponseTx = yield createGtxObject([keypairA]); mockTransactionRequest(mockThirtyTwoBytesBuffer, gtxResponseTx); const proofHash = Buffer.alloc(32, "a"); yield expect(fetchAndVerifyTransaction(client, mockThirtyTwoBytesBuffer, proofHash, [keypairA.pubKey])).rejects.toThrow(/Unable to verify source transaction proof/); })); it("throws error if fetched tx number of signatures mismatches", () => __awaiter(void 0, void 0, void 0, function* () { const gtxResponseTx = yield createGtxObject([keypairA]); mockTransactionRequest(mockThirtyTwoBytesBuffer, gtxResponseTx); const txProofHash = gtvHash(gtxToRawGtx(gtxResponseTx), 1); yield expect(fetchAndVerifyTransaction(client, mockThirtyTwoBytesBuffer, txProofHash, [])).rejects.toThrow(/Transaction signatures amount 1 do not match expected amount of signers 0/); })); it("throws error if transaction RID cannot be found", () => __awaiter(void 0, void 0, void 0, function* () { const gtxResponseTx = yield createGtxObject([keypairA]); const rid = getDigestToSign(gtxResponseTx, 1); const txProofHash = gtvHash(gtxToRawGtx(gtxResponseTx), 1); mockTransactionErrorOnRequest(rid, `{ error: "Can't find transaction with RID: ${rid.toString("hex")}" }`); yield expect(fetchAndVerifyTransaction(client, rid, txProofHash, [keypairA.pubKey])).rejects.toThrow(new UnexpectedStatusError(404, `{ error: "Can't find transaction with RID: ${rid.toString("hex")}" }`)); })); it("fetch and verify transaction with unordered signatures", () => __awaiter(void 0, void 0, void 0, function* () { const gtxResponseTx = yield createGtxObject([keypairA, keypairB]); const rid = getDigestToSign(gtxResponseTx, 1); const txProofHash = gtvHash(gtxToRawGtx(gtxResponseTx), 1); mockTransactionRequest(rid, gtxResponseTx); const { verifiedTxHash, verifiedTx } = yield fetchAndVerifyTransaction(client, rid, txProofHash, [keypairB.pubKey, keypairA.pubKey]); expect(verifiedTxHash).toEqual(txProofHash); expect(verifiedTx).toEqual(gtxResponseTx); })); it("should throw MissingTransactionProof when fetchedTxHash mismatches proofHash", () => __awaiter(void 0, void 0, void 0, function* () { const proofHash = Buffer.from("SomeDifferentHash"); const gtxResponseTx = yield createGtxObject([keypairA]); const rid = getDigestToSign(gtxResponseTx, 2); mockTransactionRequest(rid, gtxResponseTx); yield expect(fetchAndVerifyTransaction(client, rid, proofHash, [keypairA.pubKey])).rejects.toThrow(MissingTransactionProof); })); it("throws DifferentNumberOfSignersException for mismatched signature count", () => __awaiter(void 0, void 0, void 0, function* () { const gtxResponseTx = yield createGtxObject([keypairA]); const rid = getDigestToSign(gtxResponseTx, 1); const txProofHash = gtvHash(gtxToRawGtx(gtxResponseTx), 1); mockTransactionRequest(rid, gtxResponseTx); yield expect(fetchAndVerifyTransaction(client, rid, txProofHash, [keypairA.pubKey, keypairB.pubKey])).rejects.toThrow(DifferentNumberOfSignersException); })); it("throws SignatureException if signer did not sign transaction", () => __awaiter(void 0, void 0, void 0, function* () { const gtxResponseTx = yield createGtxObject([keypairA]); const rid = getDigestToSign(gtxResponseTx, 1); const txProofHash = gtvHash(gtxToRawGtx(gtxResponseTx), 1); mockTransactionRequest(rid, gtxResponseTx); yield expect(fetchAndVerifyTransaction(client, rid, txProofHash, [keypairB.pubKey])).rejects.toThrow(SignatureException); })); it("throws ProofRidException when fetched transaction RID differs", () => __awaiter(void 0, void 0, void 0, function* () { const gtxResponseTx = yield createGtxObject([keypairA]); const gtxFalseResponseTx = yield createGtxObject([keypairA], [{ opName: "fakeOperation", args: ["foo"] }]); const rid = getDigestToSign(gtxResponseTx, 1); mockTransactionRequest(rid, gtxFalseResponseTx); yield expect(fetchAndVerifyTransaction(client, rid, gtvHash(gtxToRawGtx(gtxFalseResponseTx), MERKLE_HASH_VERSIONS.ONE), [keypairA.pubKey])).rejects.toThrow(ProofRidException); })); }); describe("getClusterOfBlockchain", () => { it("returns cluster name", () => __awaiter(void 0, void 0, void 0, function* () { const serverReturnCluster = "system"; server.use(http.post(`${LOCAL_POOL}/query_gtv/${mockStringBlockchainRid}`, () => HttpResponse.arrayBuffer(encodeValue(serverReturnCluster), { status: 200, headers: { "Content-Type": contentTypes.octetStream }, }))); const res = yield getClusterOfBlockchain(client, mockBufferBlockchainRid); expect(res).toEqual(serverReturnCluster); })); it("throws error if query fails", () => __awaiter(void 0, void 0, void 0, function* () { const serverReturn = toBuffer(`{"error": "Missing query type"}`); server.use(http.post(`${LOCAL_POOL}/query_gtv/${mockStringBlockchainRid}`, () => new HttpResponse(`{ message: ${serverReturn} }`, { status: 400 }))); yield expect(getClusterOfBlockchain(client, mockBufferBlockchainRid)).rejects.toThrow(SystemChainException); yield expect(getClusterOfBlockchain(client, mockBufferBlockchainRid)).rejects.toThrow(serverReturn.toString()); })); }); describe("getClusterInfo", () => { it("should throw error if query to get cluster info fails", () => __awaiter(void 0, void 0, void 0, function* () { const serverReturn = toBuffer(`{"error": "Missing query type"}`); server.use(http.post(`${LOCAL_POOL}/query_gtv/${mockStringBlockchainRid}`, () => { return new HttpResponse(`{ message: ${serverReturn}}`, { status: 400, }); })); yield expect(getClusterOfBlockchain(client, mockBufferBlockchainRid)).rejects.toThrow(SystemChainException); })); }); describe("getAnchoringTransactionForBlockRid", () => { it("should throw error if query to get anchoring tx fails", () => __awaiter(void 0, void 0, void 0, function* () { const apiResponse = `{error": "Missing query type"}`; server.use(http.post(`${LOCAL_POOL}/query_gtv/${mockStringBlockchainRid}`, () => { return new HttpResponse(`${apiResponse}`, { status: 400, }); })); try { yield getAnchoringTransactionForBlockRid(client, mockBufferBlockchainRid, mockThirtyTwoBytesBuffer); } catch (error) { expect(error).toBeInstanceOf(SystemChainException); expect(error.message).toContain(`Query to system chain failed with error: Unexpected status code from server. Code: 400. Message: ${apiResponse}.`); } })); }); describe("calculateBlockRID", () => { it("calculates block rid from a decoded proof", () => { const arrayHeader = createHeaderArray(); const decodedTxProof = { blockHeader: encodeValue(arrayHeader), }; const sourceBlockRid = calculateBlockRID(decodedTxProof, 2); expect(sourceBlockRid).toEqual(gtvHash(arrayHeader, 2)); }); it("throws an error when blockHeader is undefined", () => { const decodedTxProof = { blockHeader: undefined, }; expect(() => { calculateBlockRID(decodedTxProof, 2); }).toThrow("Failed to get blockHeader from confirmation proof"); }); it("throws an error when block header can not be decoded", () => { const decodedTxProof = { blockHeader: mockThirtyTwoBytesBuffer, }; expect(() => { calculateBlockRID(decodedTxProof, 2); }).toThrow("Choice not matched at: (shallow)"); }); }); }); //# sourceMappingURL=iccf.test.js.map