postchain-client
Version:
Client library for accessing a Postchain node through REST.
236 lines • 8.25 kB
JavaScript
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 * as gtv from "../gtv";
import { checkDigestSignature, createPublicKey, makeKeyPair, signDigest, } from "../encryption/encryption";
import { AlreadySignedTransactionException, MissingGtxException, MissingSignerException, } from "./errors";
import { encode as gtxEncode, decode as gtxDecode } from "./index";
import { ensureBuffer } from "../formatter";
export function emptyGtx(blockchainRid) {
return { blockchainRid, operations: [], signers: [] };
}
/**
* Adds a function call to a GTX. Creates a new GTX if none specified.
* This function will throw Error if gtx is already signed
* @param opName the name of the function to call
* @param args the array of arguments of the function call. If no args, this must be an empty array
* @param gtx the function call will be added to this gtx
* @returns the gtx
* @throws if gtx is null or if gtx is already signed
*/
export function addTransactionToGtx(opName, args, gtx) {
if (gtx == null) {
throw new MissingGtxException();
}
if (gtx.signatures) {
throw new AlreadySignedTransactionException("function");
}
gtx.operations.push({ opName: opName, args: args });
return gtx;
}
export function addSignerToGtx(signer, gtx) {
if (gtx.signatures) {
throw new AlreadySignedTransactionException("signer");
}
gtx.signers.push(signer);
}
/**
* Serializes the gtx to get tx hash
* @param gtx the gtx to serialize
*/
export function getDigest(gtx) {
return gtv.gtvHash(gtxToRawGtx(gtx));
}
/**
* Serializes the gtx for signing
* @param gtx the gtx to serialize
*/
export function getDigestToSign(gtx) {
return gtv.gtvHash(gtxToRawGtxBody(gtx));
}
export function getDigestToSignFromRawGtxBody(gtxBody) {
return gtv.gtvHash(gtxBody);
}
export function gtxToRawGtxBody(gtx) {
return [
gtx.blockchainRid,
gtx.operations.map((op) => [op.opName, op.args]),
gtx.signers,
];
}
export function gtxToRawGtx(gtx) {
var _a;
return [
[
gtx.blockchainRid,
gtx.operations.map((op) => [op.opName, op.args]),
gtx.signers,
],
(_a = gtx.signatures) !== null && _a !== void 0 ? _a : [],
];
}
export function sign(gtx, privOrSigProv, pubKey) {
return __awaiter(this, void 0, void 0, function* () {
if (privOrSigProv instanceof Buffer) {
const digestToSign = getDigestToSign(gtx);
const signature = signDigest(digestToSign, privOrSigProv);
return addSignature(pubKey || makeKeyPair(privOrSigProv).pubKey, signature, gtx);
}
else {
// Removes signatures and extract the rawgtxBody
const rawGtxBody = gtxToRawGtxBody(gtx);
const signature = yield privOrSigProv.sign(rawGtxBody);
return addSignature(privOrSigProv.pubKey, signature, gtx);
}
});
}
export function signRawTransaction(_keyPair, _rawTransaction) {
throw Error("TODO");
//TODO
//const gtx = module.exports.deserialize(rawTransaction);
//module.exports.sign(keyPair.privKey, keyPair.pubKey, gtx);
// return module.exports.serialize(gtx)
}
/**
* Adds a signature to the gtx
*/
export function addSignature(pubKeyBuffer, signatureBuffer, gtx) {
if (!gtx.signatures) {
gtx.signatures = Array(gtx.signers.length);
}
const signerIndex = gtx.signers.findIndex((signer) => pubKeyBuffer.equals(signer));
if (signerIndex === -1) {
throw new MissingSignerException();
}
gtx.signatures[signerIndex] = signatureBuffer;
return gtx;
}
export function serialize(gtx) {
if (!gtx.signatures) {
// TODO
// The gtx is not signed, but we must include
// the signatures attribute, so let's add that.
gtx.signatures = [];
}
return gtxEncode([gtxToRawGtxBody(gtx), gtx.signatures]);
}
export function deserialize(gtxBytes) {
const deserializedTx = gtxDecode(gtxBytes);
const body = deserializedTx[0];
const gtvTxBody = {
blockchainRid: body[0],
operations: body[1].map((operation) => ({
opName: operation[0],
args: operation[1],
})),
signers: body[2],
};
const signatures = deserializedTx[1];
return {
blockchainRid: gtvTxBody.blockchainRid,
operations: gtvTxBody.operations,
signers: gtvTxBody.signers,
signatures,
};
}
export function checkGTXSignatures(txHash, gtx) {
var _a;
for (const i in gtx.signers) {
const signValid = checkDigestSignature(txHash, gtx.signers[i], (_a = gtx.signatures) === null || _a === void 0 ? void 0 : _a[i]);
if (!signValid)
return signValid;
}
return true;
}
export function checkExistingGTXSignatures(txHash, gtx) {
var _a;
for (const i in gtx.signers) {
if ((_a = gtx.signatures) === null || _a === void 0 ? void 0 : _a[i]) {
const signValid = checkDigestSignature(txHash, gtx.signers[i], gtx.signatures[i]);
if (!signValid)
return signValid;
}
}
return true;
}
export function newSignatureProvider(keyPair) {
let pub, priv;
if (keyPair) {
priv = ensureBuffer(keyPair.privKey);
pub = keyPair.pubKey ? ensureBuffer(keyPair.pubKey) : createPublicKey(priv);
}
else {
({ privKey: priv, pubKey: pub } = makeKeyPair());
}
return {
pubKey: pub,
sign: (gtx) => __awaiter(this, void 0, void 0, function* () {
const signature = getDigestToSignFromRawGtxBody(gtx);
return signDigest(signature, priv);
}),
};
}
export function rawGtvToGtx(gtv) {
if (Array.isArray(gtv) && gtv.length !== 2) {
throw new Error("Gtv must be an array of size 2");
}
const gtvArray = gtv;
if (!Array.isArray(gtvArray[0])) {
throw new Error("First element must be an array");
}
if (!Array.isArray(gtvArray[1])) {
throw new Error("Second element must be an array");
}
gtvArray[1].forEach((element) => {
if (!Buffer.isBuffer(element)) {
throw new Error("Element must be a buffer");
}
});
const gtxBody = rawGtvToGtxBody(gtvArray[0]);
return Object.assign(Object.assign({}, gtxBody), { signatures: gtvArray[1] });
}
function rawGtvToGtxBody(gtv) {
if (Array.isArray(gtv) && gtv.length !== 3) {
throw new Error("Gtv must be an array of size 3");
}
const array = gtv;
if (!Buffer.isBuffer(array[0])) {
throw new Error("First element must be a byte array");
}
if (!Array.isArray(array[1])) {
throw new Error("Second element must be an array");
}
if (!Array.isArray(array[2])) {
throw new Error("Third element must be an array");
}
array[2].forEach((element) => {
if (!Buffer.isBuffer(element)) {
throw new Error("Element must be a buffer");
}
});
return {
blockchainRid: array[0],
operations: array[1].map((element) => rawGtvToRellOp(element)),
signers: array[2],
};
}
function rawGtvToRellOp(gtv) {
if (Array.isArray(gtv) && gtv.length !== 2) {
throw new Error("Gtv must be an array of size 2");
}
const array = gtv;
if (typeof array[0] !== "string") {
throw new Error("First element must be a string");
}
if (!Array.isArray(array[1])) {
throw new Error("Second element must be an array");
}
return { opName: array[0], args: array[1] };
}
//# sourceMappingURL=gtx.js.map