UNPKG

@ton/core

Version:

Core TypeScript library that implements low level primitives for TON blockchain.

184 lines (152 loc) 5.23 kB
/** * Copyright (c) Whales Corp. * All Rights Reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import { BitString } from "../BitString"; import { CellType } from "../CellType"; import { Cell } from '../Cell'; import { LevelMask } from "./LevelMask"; import { ExoticPruned, exoticPruned } from "./exoticPruned"; import { exoticMerkleProof } from "./exoticMerkleProof"; import { getRepr } from "./descriptor"; import { sha256_sync } from "@ton/crypto"; import { exoticMerkleUpdate } from "./exoticMerkleUpdate"; import { exoticLibrary } from "./exoticLibrary"; // // This function replicates unknown logic of resolving cell data // https://github.com/ton-blockchain/ton/blob/24dc184a2ea67f9c47042b4104bbb4d82289fac1/crypto/vm/cells/DataCell.cpp#L214 // export function wonderCalculator(type: CellType, bits: BitString, refs: Cell[]): { mask: LevelMask, hashes: Buffer[], depths: number[] } { // // Resolving level mask // let levelMask: LevelMask; let pruned: ExoticPruned | null = null; if (type === CellType.Ordinary) { let mask = 0; for (let r of refs) { mask = mask | r.mask.value; } levelMask = new LevelMask(mask); } else if (type === CellType.PrunedBranch) { // Parse pruned pruned = exoticPruned(bits, refs); // Load level levelMask = new LevelMask(pruned.mask); } else if (type === CellType.MerkleProof) { // Parse proof let loaded = exoticMerkleProof(bits, refs); // Load level levelMask = new LevelMask(refs[0].mask.value >> 1); } else if (type === CellType.MerkleUpdate) { // Parse update let loaded = exoticMerkleUpdate(bits, refs); // Load level levelMask = new LevelMask((refs[0].mask.value | refs[1].mask.value) >> 1); } else if (type === CellType.Library) { // Parse library let loaded = exoticLibrary(bits, refs); // Load level levelMask = new LevelMask(); } else { throw new Error("Unsupported exotic type"); } // // Calculate hashes and depths // NOTE: https://github.com/ton-blockchain/ton/blob/24dc184a2ea67f9c47042b4104bbb4d82289fac1/crypto/vm/cells/DataCell.cpp#L214 // let depths: number[] = []; let hashes: Buffer[] = []; let hashCount = type === CellType.PrunedBranch ? 1 : levelMask.hashCount; let totalHashCount = levelMask.hashCount; let hashIOffset = totalHashCount - hashCount; for (let levelI = 0, hashI = 0; levelI <= levelMask.level; levelI++) { if (!levelMask.isSignificant(levelI)) { continue; } if (hashI < hashIOffset) { hashI++; continue; } // // Bits // let currentBits: BitString; if (hashI === hashIOffset) { if (!(levelI === 0 || type === CellType.PrunedBranch)) { throw Error('Invalid'); } currentBits = bits; } else { if (!(levelI !== 0 && type !== CellType.PrunedBranch)) { throw Error('Invalid: ' + levelI + ', ' + type); } currentBits = new BitString(hashes[hashI - hashIOffset - 1], 0, 256); } // // Depth // let currentDepth = 0; for (let c of refs) { let childDepth: number; if (type == CellType.MerkleProof || type == CellType.MerkleUpdate) { childDepth = c.depth(levelI + 1); } else { childDepth = c.depth(levelI); } currentDepth = Math.max(currentDepth, childDepth); } if (refs.length > 0) { currentDepth++; } // // Hash // let repr = getRepr(bits, currentBits, refs, levelI, levelMask.apply(levelI).value, type); let hash = sha256_sync(repr); // // Persist next // let destI = hashI - hashIOffset; depths[destI] = currentDepth; hashes[destI] = hash; // // Next // hashI++; } // // Calculate hash and depth for all levels // let resolvedHashes: Buffer[] = []; let resolvedDepths: number[] = []; if (pruned) { for (let i = 0; i < 4; i++) { const { hashIndex } = levelMask.apply(i); const { hashIndex: thisHashIndex } = levelMask; if (hashIndex !== thisHashIndex) { resolvedHashes.push(pruned.pruned[hashIndex].hash); resolvedDepths.push(pruned.pruned[hashIndex].depth); } else { resolvedHashes.push(hashes[0]); resolvedDepths.push(depths[0]); } } } else { for (let i = 0; i < 4; i++) { resolvedHashes.push(hashes[levelMask.apply(i).hashIndex]); resolvedDepths.push(depths[levelMask.apply(i).hashIndex]); } } // // Result // return { mask: levelMask, hashes: resolvedHashes, depths: resolvedDepths }; }