@ton/core
Version:
Core TypeScript library that implements low level primitives for TON blockchain.
171 lines (150 loc) • 6.42 kB
text/typescript
/**
* 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));
}
});
});