UNPKG

@ton/core

Version:

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

171 lines (150 loc) 6.42 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 { beginCell, Builder } from "../boc/Builder"; import { Cell } from "../boc/Cell"; import { exoticMerkleProof } from "../boc/cell/exoticMerkleProof"; import { exoticMerkleUpdate } from "../boc/cell/exoticMerkleUpdate"; import { Dictionary } from "./Dictionary"; import fs from 'fs'; import { BitString } from "../boc/BitString"; function storeBits(builder: Builder, src: string) { for (let s of src) { if (s === '0') { builder.storeBit(0); } else { builder.storeBit(1); } } return builder; } describe('Dictionary', () => { it('should parse and serialize dict from example', () => { let root = storeBits(beginCell(), '11001000') .storeRef(storeBits(beginCell(), '011000') .storeRef(storeBits(beginCell(), '1010011010000000010101001')) .storeRef(storeBits(beginCell(), '1010000010000000100100001')) ) .storeRef(storeBits(beginCell(), '1011111011111101111100100001')) .endCell(); // Unpack let dict = Dictionary.loadDirect(Dictionary.Keys.Uint(16), Dictionary.Values.Uint(16), root.beginParse()); expect(dict.get(13)).toBe(169); expect(dict.get(17)).toBe(289); expect(dict.get(239)).toBe(57121); // Empty let fromEmpty = Dictionary.empty<number, number>(); fromEmpty.set(13, 169); fromEmpty.set(17, 289); fromEmpty.set(239, 57121); // Pack let packed = beginCell() .storeDictDirect(dict) .endCell(); let packed2 = beginCell() .storeDictDirect(fromEmpty, Dictionary.Keys.Uint(16), Dictionary.Values.Uint(16)) .endCell(); // Compare expect(packed.equals(root)).toBe(true); expect(packed2.equals(root)).toBe(true); }); it('should parse config', () => { let cell = Cell.fromBoc(Buffer.from(fs.readFileSync(__dirname + '/__testdata__/config.txt', 'utf-8'), 'base64'))[0]; let configs = cell.beginParse().loadDictDirect(Dictionary.Keys.Int(32), Dictionary.Values.Cell()); let ids: number[] = [0, 1, 2, 4, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 28, 29, 31, 32, 34, 71, 72, -999, -71]; let keys = configs.keys(); for (let i of ids) { expect(keys).toContain(i); expect(configs.get(i)).not.toBeUndefined(); expect(configs.has(i)).toBe(true); } }); it('should parse bridge config', () => { let cell = Cell.fromBoc(Buffer.from(fs.readFileSync(__dirname + '/__testdata__/config.txt', 'utf-8'), 'base64'))[0]; let configs = cell.beginParse().loadDictDirect(Dictionary.Keys.Int(32), Dictionary.Values.Cell()); for (let i of [71, 72]) { let r = configs.get(i)!; let config = r.beginParse(); let bridgeAddress = config.loadBuffer(32); let oracleMultisigAddress = config.loadBuffer(32); let oracles = config.loadDict(Dictionary.Keys.BigUint(256), Dictionary.Values.Buffer(32)); let externalChainAddress = config.loadBuffer(32); // console.warn(oracles); } }); it('should parse dictionary with empty values', () => { let cell = Cell.fromBoc(Buffer.from(fs.readFileSync(__dirname + "/__testdata__/empty_value.boc")))[0]; let testDict = Dictionary.loadDirect(Dictionary.Keys.BigUint(256), Dictionary.Values.BitString(0), cell); expect(testDict.keys()[0]).toEqual(123n); expect(testDict.get(123n)!.length).toBe(0); }); it('should correctly serialize BitString keys and values', () => { const keyLen = 9; // Not 8 bit aligned const keys = Dictionary.Keys.BitString(keyLen); const values = Dictionary.Values.BitString(72); let testKey = new BitString(Buffer.from("Test"), 0, keyLen); let testVal = new BitString(Buffer.from("BitString"), 0, 72); let testDict = Dictionary.empty(keys, values); testDict.set(testKey, testVal); expect(testDict.get(testKey)!.equals(testVal)).toBe(true); let serialized = beginCell().storeDictDirect(testDict).endCell(); let dictDs = Dictionary.loadDirect(keys, values, serialized); expect(dictDs.get(testKey)!.equals(testVal)).toBe(true); }); it('should generate merkle proofs', () => { let d = Dictionary.empty( Dictionary.Keys.Uint(8), Dictionary.Values.Uint(32) ); d.set(1, 11); d.set(2, 22); d.set(3, 33); d.set(4, 44); d.set(5, 55); const dictHash = beginCell().storeDictDirect(d).endCell().hash(); for (let k = 1; k <= 5; k++) { const proof = d.generateMerkleProof([k]); Cell.fromBoc(proof.toBoc()); expect(exoticMerkleProof(proof.bits, proof.refs).proofHash).toEqual( dictHash ); // todo: parse the pruned dictionary and check the presence of the keys } for (let k = 1; k <= 3; k++) { const proof = d.generateMerkleProof([k, k + 1, k + 2]); Cell.fromBoc(proof.toBoc()); expect(exoticMerkleProof(proof.bits, proof.refs).proofHash).toEqual( dictHash ); } expect(() => d.generateMerkleProof([6])).toThrow(); }); it('should generate merkle updates', () => { let d = Dictionary.empty( Dictionary.Keys.Uint(8), Dictionary.Values.Uint(32) ); d.set(1, 11); d.set(2, 22); d.set(3, 33); d.set(4, 44); d.set(5, 55); for (let k = 1; k <= 5; k++) { const update = d.generateMerkleUpdate(k, d.get(k)! * 2); Cell.fromBoc(update.toBoc()); expect( exoticMerkleUpdate(update.bits, update.refs).proofHash1 ).toEqual( Buffer.from( 'ee41b86bd71f8224ebd01848b4daf4cd46d3bfb3e119d8b865ce7c2802511de3', 'hex' ) ); d.set(k, Math.floor(d.get(k)! / 2)); } }); });