Skip to content
Snippets Groups Projects
Commit 4b99eb3d authored by Igor Markin's avatar Igor Markin
Browse files

Add build

parent 7b6bed30
No related branches found
No related tags found
1 merge request!70[Status verification improvement] Implement new improved status verification
import { TxData, TxMerkleTreeData } from "../../types";
import { TxData, DecodedCallData } from "../../types";
import { Request } from "../../utils/requestAdapter";
declare class AeternityService {
readonly _nodeUrls: any[];
......@@ -14,7 +14,7 @@ declare class AeternityService {
*/
requestApi: (apiUrls: string[]) => Request;
getTxDataByHash(hash: string): Promise<TxData>;
decodeContractCallData(callData: string): Promise<TxMerkleTreeData>;
decodeContractCallData(callData: string): Promise<DecodedCallData>;
getBlock(height: number): Promise<{
height: number;
time: number;
......
......@@ -101,8 +101,8 @@ class AeternityService {
},
}));
return {
merkleeTreeFileName: (_c = (_b = (_a = data.arguments[0]) === null || _a === void 0 ? void 0 : _a.value[0]) === null || _b === void 0 ? void 0 : _b.key) === null || _c === void 0 ? void 0 : _c.value,
rootNodeHash: (_f = (_e = (_d = data.arguments[0]) === null || _d === void 0 ? void 0 : _d.value[0]) === null || _e === void 0 ? void 0 : _e.val) === null || _f === void 0 ? void 0 : _f.value,
key: (_c = (_b = (_a = data.arguments[0]) === null || _a === void 0 ? void 0 : _a.value[0]) === null || _b === void 0 ? void 0 : _b.key) === null || _c === void 0 ? void 0 : _c.value,
value: (_f = (_e = (_d = data.arguments[0]) === null || _d === void 0 ? void 0 : _d.value[0]) === null || _e === void 0 ? void 0 : _e.val) === null || _f === void 0 ? void 0 : _f.value,
};
});
}
......
declare const EventEmitter: any;
import { BlockData, MerkleTree, StatusData, TxData, VerificationData } from "../../types";
import { BlockData, StatusesBatchData, StatusData, TxData, VerificationData } from "../../types";
import { AxiosError } from "axios";
export declare const TRANSACTION_RETRIEVED = "TRANSACTION_RETRIEVED";
export declare const MERKLE_TREE_VERIFIED = "MERKLE_TREE_VERIFIED";
export declare const STATUS_BATCH_VERIFIED = "STATUS_BATCH_VERIFIED";
export declare const BLOCK_DATA_RETRIEVED = "BLOCK_DATA_RETRIEVED";
declare class VerificationService extends EventEmitter {
private _aeternityService;
......@@ -11,8 +12,15 @@ declare class VerificationService extends EventEmitter {
getTransaction(hash: string): Promise<TxData>;
getBlockData(blockHeight: number): Promise<BlockData>;
verifyStatusData(statusData: StatusData): Promise<VerificationData>;
getMerkleTreeForTransaction(txData: TxData): Promise<MerkleTree>;
verifyMerkleTreeNode(nodeToVerify: string, merkleTree: MerkleTree): Promise<boolean>;
getStatusBatchDataForTx(txData: TxData): Promise<StatusesBatchData>;
verifyStatusSHA256Batch(status: string, statusesBatchData: StatusesBatchData): Promise<{
verified: boolean;
statusPosition: number;
}>;
verifyStatusesMerkleTree(nodeToVerify: string, merkleTree: StatusesBatchData): Promise<{
verified: boolean;
statusPosition: number;
}>;
catchVerificationError(error: AxiosError, verificationFailureMessage: string): void;
}
export default VerificationService;
......@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BLOCK_DATA_RETRIEVED = exports.MERKLE_TREE_VERIFIED = exports.TRANSACTION_RETRIEVED = void 0;
exports.BLOCK_DATA_RETRIEVED = exports.STATUS_BATCH_VERIFIED = exports.MERKLE_TREE_VERIFIED = exports.TRANSACTION_RETRIEVED = void 0;
const index_1 = require("../../index");
const EventEmitter = require("eventemitter2");
const AeternityService_1 = __importDefault(require("../AeternityService/AeternityService"));
......@@ -20,7 +20,15 @@ const CloudflareService_1 = __importDefault(require("../CloudflareService"));
const VerificationError_1 = __importDefault(require("./VerificationError"));
exports.TRANSACTION_RETRIEVED = "TRANSACTION_RETRIEVED";
exports.MERKLE_TREE_VERIFIED = "MERKLE_TREE_VERIFIED";
exports.STATUS_BATCH_VERIFIED = "STATUS_BATCH_VERIFIED";
exports.BLOCK_DATA_RETRIEVED = "BLOCK_DATA_RETRIEVED";
/**
* Legacy verification method. Support for older statuses
*/
const VERIFICATION_METHOD_MERKLE_TREE = "VERIFICATION_METHOD_MERKLE_TREE";
const VERIFICATION_METHOD_SHA256_BATCH = "VERIFICATION_METHOD_SHA256_BATCH";
const STATUSES_BATCH_NAME_PREFIX = "batch";
const STATUSES_MERKLE_TREE_NAME_PREFIX = "bmt";
class VerificationService extends EventEmitter {
constructor(cdnUrl, cdnBucket, aeternityNodeUrls, aeternityCompilerUrls, aeternityContractBytecode) {
super();
......@@ -78,20 +86,34 @@ class VerificationService extends EventEmitter {
return __awaiter(this, void 0, void 0, function* () {
let verificationError;
let blockData;
let merkleTreeDetails;
let batchVerificationDetails;
let txData;
try {
txData = yield this.getTransaction(statusData.transactionHash);
this.emit(exports.TRANSACTION_RETRIEVED, txData);
const merkleTree = yield this.getMerkleTreeForTransaction(txData);
const statusVerified = yield this.verifyMerkleTreeNode(statusData.statusRaw, merkleTree);
merkleTreeDetails = {
const statusBatchData = yield this.getStatusBatchDataForTx(txData);
const { verificationMethod, items: batchItems, hash: batchHash, } = statusBatchData;
let statusVerified;
let statusPosition = -1;
if (verificationMethod === VERIFICATION_METHOD_MERKLE_TREE) {
({
verified: statusVerified,
statusPosition,
} = yield this.verifyStatusesMerkleTree(statusData.statusRaw, statusBatchData));
}
else if (verificationMethod === VERIFICATION_METHOD_SHA256_BATCH) {
({
verified: statusVerified,
statusPosition,
} = yield this.verifyStatusSHA256Batch(statusData.statusRaw, statusBatchData));
}
batchVerificationDetails = {
verified: statusVerified,
treeSize: merkleTree.nodes.length,
statusPosition: merkleTree.nodes.indexOf(statusData.statusRaw) + 1,
rootHash: merkleTree.rootHash,
batchSize: batchItems.length,
statusPosition,
batchHash,
};
this.emit(exports.MERKLE_TREE_VERIFIED, merkleTreeDetails);
this.emit(exports.STATUS_BATCH_VERIFIED, batchVerificationDetails);
blockData = yield this.getBlockData(txData.blockHeight);
this.emit(exports.BLOCK_DATA_RETRIEVED, blockData);
}
......@@ -105,38 +127,94 @@ class VerificationService extends EventEmitter {
}
return {
statusData,
merkleTreeDetails,
batchVerificationDetails,
blockData,
verificationError,
txData,
};
});
}
getMerkleTreeForTransaction(txData) {
getStatusBatchDataForTx(txData) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
let verificationMethod;
let batchItems;
let decodedCallData;
try {
const txMerkleTreeData = yield this._aeternityService.decodeContractCallData((_a = txData.tx) === null || _a === void 0 ? void 0 : _a.callData);
const merkleTreeNodes = yield this._cloudflareService.getMerkleTree(txMerkleTreeData.merkleeTreeFileName);
return {
nodes: merkleTreeNodes,
rootHash: txMerkleTreeData.rootNodeHash,
};
decodedCallData = yield this._aeternityService.decodeContractCallData((_a = txData.tx) === null || _a === void 0 ? void 0 : _a.callData);
}
catch (e) {
this.catchVerificationError(e, `Error extracting Merkle tree from transaction.`);
this.catchVerificationError(e, `Error decoding contract call data`);
}
const { key: batchFilename, value } = decodedCallData;
const batchHash = value;
const lowerCaseFilename = batchFilename.toLowerCase();
if (lowerCaseFilename.startsWith(STATUSES_MERKLE_TREE_NAME_PREFIX)) {
verificationMethod = VERIFICATION_METHOD_MERKLE_TREE;
}
else if (lowerCaseFilename.startsWith(STATUSES_BATCH_NAME_PREFIX)) {
verificationMethod = VERIFICATION_METHOD_SHA256_BATCH;
}
else {
// Unrecognized verification method
throw new VerificationError_1.default(`No corresponding verification method found for batch "${batchFilename}"`);
}
try {
if (verificationMethod === VERIFICATION_METHOD_MERKLE_TREE) {
batchItems = yield this._cloudflareService.getMerkleTree(batchFilename);
}
else if (verificationMethod === VERIFICATION_METHOD_SHA256_BATCH) {
batchItems = (yield this._cloudflareService.fetchFile(batchFilename));
}
}
catch (e) {
this.catchVerificationError(e, `Error obtaining batch of statuses for verification.`);
}
return {
verificationMethod,
hash: batchHash,
items: batchItems,
};
});
}
verifyStatusSHA256Batch(status, statusesBatchData) {
return __awaiter(this, void 0, void 0, function* () {
const statusSha256 = index_1.arrayBufferToBase64(yield index_1.CryptoService.SHA256(status, "base64"));
let verified = false;
const statusPosition = statusesBatchData.items.indexOf(statusSha256) + 1;
if (statusPosition > 0) {
const bytesToHash = [];
let hashesTotalByteLength = 0;
for (const statusHash of statusesBatchData.items) {
const statusHashBytes = index_1.base64ToArrayBuffer(statusHash);
hashesTotalByteLength += statusHashBytes.byteLength;
bytesToHash.push(new Uint8Array(statusHashBytes));
}
const batchBytes = new Uint8Array(hashesTotalByteLength);
let bytesOffset = 0;
bytesToHash.forEach((statusHashBytes) => {
batchBytes.set(statusHashBytes, bytesOffset);
bytesOffset += statusHashBytes.byteLength;
});
const batchHash = index_1.arrayBufferToBase64(yield index_1.CryptoService.SHA256(batchBytes));
verified = batchHash === statusesBatchData.hash;
}
return {
verified,
statusPosition,
};
});
}
verifyMerkleTreeNode(nodeToVerify, merkleTree) {
verifyStatusesMerkleTree(nodeToVerify, merkleTree) {
return __awaiter(this, void 0, void 0, function* () {
const leaves = yield Promise.all(merkleTree.nodes.map((x) => __awaiter(this, void 0, void 0, function* () { return Buffer.from(yield index_1.CryptoService.SHA256(x)); })));
const leaves = yield Promise.all(merkleTree.items.map((x) => __awaiter(this, void 0, void 0, function* () { return Buffer.from(yield index_1.CryptoService.SHA256(x)); })));
const rootHash = (yield index_1.getMerkleTreeRootHash(leaves)).toString("base64");
const verified = rootHash === merkleTree.rootHash;
const verified = rootHash === merkleTree.hash;
if (!verified) {
throw new VerificationError_1.default(`Merkle tree not verified.`);
}
return verified;
const statusPosition = merkleTree.items.indexOf(nodeToVerify) + 1;
return { verified, statusPosition };
});
}
catchVerificationError(error, verificationFailureMessage) {
......
......@@ -29,21 +29,22 @@ export interface StatusData {
merkleTreeId: string;
transactionHash: string;
}
export interface MerkleTreeVerificationDetails {
export interface BatchVerificationDetails {
statusPosition: number;
treeSize: number;
batchSize: number;
verified: boolean;
rootHash: string;
batchHash: string;
}
export interface MerkleTree {
rootHash: string;
nodes: Array<string>;
export interface StatusesBatchData {
verificationMethod: string;
hash: string;
items: Array<string>;
}
export interface VerificationData {
statusData?: StatusData;
blockData?: BlockData;
txData?: TxData;
merkleTreeDetails?: MerkleTreeVerificationDetails;
batchVerificationDetails?: BatchVerificationDetails;
verificationError?: VerificationError;
}
export interface BlockData {
......@@ -58,9 +59,9 @@ export interface TxData {
callData: string;
};
}
export interface TxMerkleTreeData {
merkleeTreeFileName: string;
rootNodeHash: string;
export interface DecodedCallData {
key: string;
value: string;
}
export interface AttachmentSignature {
value: string;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment