Comparing version 0.52.0 to 0.53.0
@@ -83,3 +83,3 @@ "use strict"; | ||
// hash is not valid | ||
if (!/[a-f][0-9]+/.test(hash.toLowerCase())) { | ||
if (!/[a-f0-9]+/.test(hash.toLowerCase())) { | ||
return false; | ||
@@ -86,0 +86,0 @@ } |
@@ -16,2 +16,3 @@ "use strict"; | ||
let address3 = Address_1.Address.parseRaw('0:2cf55953e92efbeadab7ba725c3f93a0b23f842cbba72d7b8e6f510a70e422e3'); | ||
let address4 = Address_1.Address.parse('-1:3333333333333333333333333333333333333333333333333333333333333333'); | ||
expect(address1.isBounceable).toBe(false); | ||
@@ -30,2 +31,4 @@ expect(address2.isBounceable).toBe(true); | ||
expect(address3.toRawString()).toBe('0:2cf55953e92efbeadab7ba725c3f93a0b23f842cbba72d7b8e6f510a70e422e3'); | ||
expect(address4.workChain).toBe(-1); | ||
expect(address4.hash).toEqual(Buffer.from('3333333333333333333333333333333333333333333333333333333333333333', 'hex')); | ||
}); | ||
@@ -32,0 +35,0 @@ it('should serialize to friendly form', () => { |
@@ -19,2 +19,8 @@ /** | ||
/** | ||
* Checks if supplied object is BitString | ||
* @param src is unknow object | ||
* @returns true if object is BitString and false otherwise | ||
**/ | ||
static isBitString(src: unknown): src is BitString; | ||
/** | ||
* Constructing BitString from a buffer | ||
@@ -21,0 +27,0 @@ * @param data data that contains the bitstring data. NOTE: We are expecting this buffer to be NOT modified |
@@ -22,2 +22,10 @@ "use strict"; | ||
/** | ||
* Checks if supplied object is BitString | ||
* @param src is unknow object | ||
* @returns true if object is BitString and false otherwise | ||
**/ | ||
static isBitString(src) { | ||
return src instanceof BitString; | ||
} | ||
/** | ||
* Constructing BitString from a buffer | ||
@@ -72,3 +80,3 @@ * @param data data that contains the bitstring data. NOTE: We are expecting this buffer to be NOT modified | ||
// Check offset | ||
if (offset >= this._length) { | ||
if (offset > this._length) { | ||
throw new Error(`Offset(${offset}) > ${this._length} is out of bounds`); | ||
@@ -97,3 +105,3 @@ } | ||
// Check offset | ||
if (offset >= this._length) { | ||
if (offset > this._length) { | ||
throw new Error(`Offset ${offset} is out of bounds`); | ||
@@ -100,0 +108,0 @@ } |
@@ -13,2 +13,14 @@ "use strict"; | ||
describe('BitString', () => { | ||
let testOOB; | ||
beforeAll(() => { | ||
testOOB = (method, bs, offset, length) => { | ||
try { | ||
let bs2 = bs[method](offset, length); | ||
throw (Error("Should fail")); | ||
} | ||
catch (e) { | ||
expect(e.message.endsWith('out of bounds')).toBe(true); | ||
} | ||
}; | ||
}); | ||
it('should read bits', () => { | ||
@@ -51,2 +63,35 @@ let bs = new BitString_1.BitString(Buffer.from([0b10101010]), 0, 8); | ||
}); | ||
it('should do substrings', () => { | ||
let bs = new BitString_1.BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
let bs2 = bs.substring(0, 16); | ||
expect(bs2.length).toBe(16); | ||
}); | ||
it('should do empty substrings with requested length 0', () => { | ||
let bs = new BitString_1.BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
let bs2 = bs.substring(bs.length, 0); | ||
expect(bs2.length).toBe(0); | ||
}); | ||
it('should OOB when substring offset is out of bounds', () => { | ||
let bs = new BitString_1.BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
testOOB('substring', bs, bs.length + 1, 0); | ||
testOOB('substring', bs, -1, 0); | ||
}); | ||
it('should OOB when subbuffer offset is out of bounds', () => { | ||
let bs = new BitString_1.BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
testOOB('subbuffer', bs, bs.length + 1, 0); | ||
testOOB('subbuffer', bs, -1, 0); | ||
}); | ||
it('should OOB when offset is on the end of bitsring and length > 0', () => { | ||
let bs = new BitString_1.BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
testOOB('substring', bs, bs.length, 1); | ||
}); | ||
it('should do empty subbuffers with requested length 0', () => { | ||
let bs = new BitString_1.BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
let bs2 = bs.subbuffer(bs.length, 0); | ||
expect(bs2.length).toBe(0); | ||
}); | ||
it('should OOB when offset is on the end of buffer and length > 0', () => { | ||
let bs = new BitString_1.BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
testOOB('subbuffer', bs, bs.length, 1); | ||
}); | ||
it('should process monkey strings', () => { | ||
@@ -53,0 +98,0 @@ let cases = [ |
@@ -11,1 +11,2 @@ /** | ||
export declare function bitsToPaddedBuffer(bits: BitString): Buffer; | ||
export declare function paddedBufferToBits(buff: Buffer): BitString; |
@@ -10,4 +10,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.bitsToPaddedBuffer = void 0; | ||
exports.paddedBufferToBits = exports.bitsToPaddedBuffer = void 0; | ||
const BitBuilder_1 = require("../BitBuilder"); | ||
const BitString_1 = require("../BitString"); | ||
function bitsToPaddedBuffer(bits) { | ||
@@ -30,1 +31,24 @@ // Create builder | ||
exports.bitsToPaddedBuffer = bitsToPaddedBuffer; | ||
function paddedBufferToBits(buff) { | ||
let bitLen = 0; | ||
// Finding rightmost non-zero byte in the buffer | ||
for (let i = buff.length - 1; i >= 0; i--) { | ||
if (buff[i] !== 0) { | ||
const testByte = buff[i]; | ||
// Looking for a rightmost set padding bit | ||
let bitPos = testByte & -testByte; | ||
if ((bitPos & 1) == 0) { | ||
// It's power of 2 (only one bit set) | ||
bitPos = Math.log2(bitPos) + 1; | ||
} | ||
if (i > 0) { | ||
// If we are dealing with more than 1 byte buffer | ||
bitLen = i << 3; //Number of full bytes * 8 | ||
} | ||
bitLen += 8 - bitPos; | ||
break; | ||
} | ||
} | ||
return new BitString_1.BitString(buff, 0, bitLen); | ||
} | ||
exports.paddedBufferToBits = paddedBufferToBits; |
@@ -13,4 +13,5 @@ /** | ||
import { Slice } from "../boc/Slice"; | ||
import { BitString } from "../boc/BitString"; | ||
import { Maybe } from "../utils/maybe"; | ||
export type DictionaryKeyTypes = Address | number | bigint | Buffer; | ||
export type DictionaryKeyTypes = Address | number | bigint | Buffer | BitString; | ||
export type DictionaryKey<K extends DictionaryKeyTypes> = { | ||
@@ -62,2 +63,11 @@ bits: number; | ||
Buffer: (bytes: number) => DictionaryKey<Buffer>; | ||
/** | ||
* Create BitString key | ||
* @param bits key length | ||
* @returns DictionaryKey<BitString> | ||
* Point is that Buffer has to be 8 bit aligned, | ||
* while key is TVM dictionary doesn't have to be | ||
* aligned at all. | ||
*/ | ||
BitString: (bits: number) => DictionaryKey<BitString>; | ||
}; | ||
@@ -121,2 +131,10 @@ static Values: { | ||
/** | ||
* Create BitString value | ||
* @param requested bit length | ||
* @returns DictionaryValue<BitString> | ||
* Point is that Buffer is not applicable | ||
* when length is not 8 bit alligned. | ||
*/ | ||
BitString: (bits: number) => DictionaryValue<BitString>; | ||
/** | ||
* Create dictionary value | ||
@@ -168,2 +186,4 @@ * @param key | ||
storeDirect(builder: Builder, key?: Maybe<DictionaryKey<K>>, value?: Maybe<DictionaryValue<V>>): void; | ||
generateMerkleProof(key: K): Cell; | ||
generateMerkleUpdate(key: K, newValue: V): Cell; | ||
} |
@@ -14,2 +14,5 @@ "use strict"; | ||
const Cell_1 = require("../boc/Cell"); | ||
const BitString_1 = require("../boc/BitString"); | ||
const generateMerkleProof_1 = require("./generateMerkleProof"); | ||
const generateMerkleUpdate_1 = require("./generateMerkleUpdate"); | ||
const parseDict_1 = require("./parseDict"); | ||
@@ -182,2 +185,8 @@ const serializeDict_1 = require("./serializeDict"); | ||
} | ||
generateMerkleProof(key) { | ||
return (0, generateMerkleProof_1.generateMerkleProof)(this, key, this._key); | ||
} | ||
generateMerkleUpdate(key, newValue) { | ||
return (0, generateMerkleUpdate_1.generateMerkleUpdate)(this, key, this._key, newValue); | ||
} | ||
} | ||
@@ -232,2 +241,13 @@ exports.Dictionary = Dictionary; | ||
return createBufferKey(bytes); | ||
}, | ||
/** | ||
* Create BitString key | ||
* @param bits key length | ||
* @returns DictionaryKey<BitString> | ||
* Point is that Buffer has to be 8 bit aligned, | ||
* while key is TVM dictionary doesn't have to be | ||
* aligned at all. | ||
*/ | ||
BitString: (bits) => { | ||
return createBitStringKey(bits); | ||
} | ||
@@ -312,2 +332,12 @@ }; | ||
/** | ||
* Create BitString value | ||
* @param requested bit length | ||
* @returns DictionaryValue<BitString> | ||
* Point is that Buffer is not applicable | ||
* when length is not 8 bit alligned. | ||
*/ | ||
BitString: (bits) => { | ||
return createBitStringValue(bits); | ||
}, | ||
/** | ||
* Create dictionary value | ||
@@ -420,2 +450,15 @@ * @param key | ||
} | ||
function createBitStringKey(bits) { | ||
return { | ||
bits, | ||
serialize: (src) => { | ||
if (!BitString_1.BitString.isBitString(src)) | ||
throw Error('Key is not a BitString'); | ||
return (0, Builder_1.beginCell)().storeBits(src).endCell().beginParse().loadUintBig(bits); | ||
}, | ||
parse: (src) => { | ||
return (0, Builder_1.beginCell)().storeUint(src, bits).endCell().beginParse().loadBits(bits); | ||
} | ||
}; | ||
} | ||
function createIntValue(bits) { | ||
@@ -534,1 +577,14 @@ return { | ||
} | ||
function createBitStringValue(bits) { | ||
return { | ||
serialize: (src, builder) => { | ||
if (src.length !== bits) { | ||
throw Error('Invalid BitString size'); | ||
} | ||
builder.storeBits(src); | ||
}, | ||
parse: (src) => { | ||
return src.loadBits(bits); | ||
} | ||
}; | ||
} |
@@ -15,4 +15,7 @@ "use strict"; | ||
const Cell_1 = require("../boc/Cell"); | ||
const exoticMerkleProof_1 = require("../boc/cell/exoticMerkleProof"); | ||
const exoticMerkleUpdate_1 = require("../boc/cell/exoticMerkleUpdate"); | ||
const Dictionary_1 = require("./Dictionary"); | ||
const fs_1 = __importDefault(require("fs")); | ||
const BitString_1 = require("../boc/BitString"); | ||
function storeBits(builder, src) { | ||
@@ -82,2 +85,48 @@ for (let s of src) { | ||
}); | ||
it('should parse dictionary with empty values', () => { | ||
let cell = Cell_1.Cell.fromBoc(Buffer.from(fs_1.default.readFileSync(__dirname + "/__testdata__/empty_value.boc")))[0]; | ||
let testDict = Dictionary_1.Dictionary.loadDirect(Dictionary_1.Dictionary.Keys.BigUint(256), Dictionary_1.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_1.Dictionary.Keys.BitString(keyLen); | ||
const values = Dictionary_1.Dictionary.Values.BitString(72); | ||
let testKey = new BitString_1.BitString(Buffer.from("Test"), 0, keyLen); | ||
let testVal = new BitString_1.BitString(Buffer.from("BitString"), 0, 72); | ||
let testDict = Dictionary_1.Dictionary.empty(keys, values); | ||
testDict.set(testKey, testVal); | ||
expect(testDict.get(testKey).equals(testVal)).toBe(true); | ||
let serialized = (0, Builder_1.beginCell)().storeDictDirect(testDict).endCell(); | ||
let dictDs = Dictionary_1.Dictionary.loadDirect(keys, values, serialized); | ||
expect(dictDs.get(testKey).equals(testVal)).toBe(true); | ||
}); | ||
it('should generate merkle proofs', () => { | ||
let d = Dictionary_1.Dictionary.empty(Dictionary_1.Dictionary.Keys.Uint(8), Dictionary_1.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 proof = d.generateMerkleProof(k); | ||
Cell_1.Cell.fromBoc(proof.toBoc()); | ||
expect((0, exoticMerkleProof_1.exoticMerkleProof)(proof.bits, proof.refs).proofHash).toEqual(Buffer.from('ee41b86bd71f8224ebd01848b4daf4cd46d3bfb3e119d8b865ce7c2802511de3', 'hex')); | ||
} | ||
}); | ||
it('should generate merkle updates', () => { | ||
let d = Dictionary_1.Dictionary.empty(Dictionary_1.Dictionary.Keys.Uint(8), Dictionary_1.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_1.Cell.fromBoc(update.toBoc()); | ||
expect((0, exoticMerkleUpdate_1.exoticMerkleUpdate)(update.bits, update.refs).proofHash1).toEqual(Buffer.from('ee41b86bd71f8224ebd01848b4daf4cd46d3bfb3e119d8b865ce7c2802511de3', 'hex')); | ||
d.set(k, Math.floor(d.get(k) / 2)); | ||
} | ||
}); | ||
}); |
@@ -12,2 +12,4 @@ "use strict"; | ||
const Address_1 = require("../../address/Address"); | ||
const BitString_1 = require("../../boc/BitString"); | ||
const paddedBits_1 = require("../../boc/utils/paddedBits"); | ||
function serializeInternalKey(value) { | ||
@@ -29,2 +31,5 @@ if (typeof value === 'number') { | ||
} | ||
else if (BitString_1.BitString.isBitString(value)) { | ||
return 'B:' + value.toString(); | ||
} | ||
else { | ||
@@ -50,4 +55,22 @@ throw Error('Invalid key type'); | ||
} | ||
else if (k === 'B:') { | ||
const lastDash = v.slice(-1) == "_"; | ||
const isPadded = lastDash || v.length % 2 != 0; | ||
if (isPadded) { | ||
let charLen = lastDash ? v.length - 1 : v.length; | ||
const padded = v.substr(0, charLen) + "0"; //Padding | ||
if ((!lastDash) && ((charLen & 1) !== 0)) { | ||
// Four bit nibmle without padding | ||
return new BitString_1.BitString(Buffer.from(padded, 'hex'), 0, charLen << 2); | ||
} | ||
else { | ||
return (0, paddedBits_1.paddedBufferToBits)(Buffer.from(padded, 'hex')); | ||
} | ||
} | ||
else { | ||
return new BitString_1.BitString(Buffer.from(v, 'hex'), 0, v.length << 2); | ||
} | ||
} | ||
throw Error('Invalid key type: ' + k); | ||
} | ||
exports.deserializeInternalKey = deserializeInternalKey; |
@@ -10,2 +10,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const BitString_1 = require("../../boc/BitString"); | ||
const testAddress_1 = require("../../utils/testAddress"); | ||
@@ -38,2 +39,12 @@ const internalKeySerializer_1 = require("./internalKeySerializer"); | ||
}); | ||
it('should serialize bit strings', () => { | ||
let cs = [Buffer.from('00', 'hex'), Buffer.from('ff', 'hex'), Buffer.from('0f', 'hex'), Buffer.from('0f000011002233456611', 'hex')]; | ||
for (let c of cs) { | ||
for (let i = 0; i < c.length * 8 - 1; i++) { | ||
let bs = new BitString_1.BitString(c, 0, c.length * 8 - i); | ||
const res = (0, internalKeySerializer_1.deserializeInternalKey)((0, internalKeySerializer_1.serializeInternalKey)(bs)); | ||
expect(res.equals(bs)).toBe(true); | ||
} | ||
} | ||
}); | ||
}); |
@@ -24,2 +24,4 @@ /** | ||
export { exoticPruned } from './boc/cell/exoticPruned'; | ||
export { generateMerkleProof } from './dict/generateMerkleProof'; | ||
export { generateMerkleUpdate } from './dict/generateMerkleUpdate'; | ||
export { Tuple, TupleItem, TupleItemNull, TupleItemInt, TupleItemNaN, TupleItemCell, TupleItemSlice, TupleItemBuilder } from './tuple/tuple'; | ||
@@ -26,0 +28,0 @@ export { parseTuple, serializeTuple } from './tuple/tuple'; |
@@ -24,3 +24,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.safeSignVerify = exports.safeSign = exports.getMethodId = exports.base32Encode = exports.base32Decode = exports.crc32c = exports.crc16 = exports.fromNano = exports.toNano = exports.ComputeError = exports.openContract = exports.TupleBuilder = exports.TupleReader = exports.serializeTuple = exports.parseTuple = exports.exoticPruned = exports.exoticMerkleUpdate = exports.exoticMerkleProof = exports.Dictionary = exports.Cell = exports.CellType = exports.Slice = exports.beginCell = exports.Builder = exports.BitBuilder = exports.BitReader = exports.BitString = exports.contractAddress = exports.ADNLAddress = exports.ExternalAddress = exports.address = exports.Address = void 0; | ||
exports.safeSignVerify = exports.safeSign = exports.getMethodId = exports.base32Encode = exports.base32Decode = exports.crc32c = exports.crc16 = exports.fromNano = exports.toNano = exports.ComputeError = exports.openContract = exports.TupleBuilder = exports.TupleReader = exports.serializeTuple = exports.parseTuple = exports.generateMerkleUpdate = exports.generateMerkleProof = exports.exoticPruned = exports.exoticMerkleUpdate = exports.exoticMerkleProof = exports.Dictionary = exports.Cell = exports.CellType = exports.Slice = exports.beginCell = exports.Builder = exports.BitBuilder = exports.BitReader = exports.BitString = exports.contractAddress = exports.ADNLAddress = exports.ExternalAddress = exports.address = exports.Address = void 0; | ||
// Address | ||
@@ -63,2 +63,7 @@ var Address_1 = require("./address/Address"); | ||
Object.defineProperty(exports, "exoticPruned", { enumerable: true, get: function () { return exoticPruned_1.exoticPruned; } }); | ||
// Merkle trees | ||
var generateMerkleProof_1 = require("./dict/generateMerkleProof"); | ||
Object.defineProperty(exports, "generateMerkleProof", { enumerable: true, get: function () { return generateMerkleProof_1.generateMerkleProof; } }); | ||
var generateMerkleUpdate_1 = require("./dict/generateMerkleUpdate"); | ||
Object.defineProperty(exports, "generateMerkleUpdate", { enumerable: true, get: function () { return generateMerkleUpdate_1.generateMerkleUpdate; } }); | ||
var tuple_1 = require("./tuple/tuple"); | ||
@@ -65,0 +70,0 @@ Object.defineProperty(exports, "parseTuple", { enumerable: true, get: function () { return tuple_1.parseTuple; } }); |
@@ -14,2 +14,3 @@ /** | ||
export { AccountStorage, loadAccountStorage, storeAccountStorage } from './AccountStorage'; | ||
export { OutActionSendMsg, OutActionSetCode, OutAction, loadOutAction, storeOutAction, loadOutList, storeOutList } from './OutList'; | ||
export { CommonMessageInfo, CommonMessageInfoInternal, CommonMessageInfoExternalIn, CommonMessageInfoExternalOut, loadCommonMessageInfo, storeCommonMessageInfo } from './CommonMessageInfo'; | ||
@@ -16,0 +17,0 @@ export { CommonMessageInfoRelaxed, CommonMessageInfoRelaxedExternalOut, CommonMessageInfoRelaxedInternal, loadCommonMessageInfoRelaxed, storeCommonMessageInfoRelaxed } from './CommonMessageInfoRelaxed'; |
@@ -10,4 +10,4 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.loadStorageUsedShort = exports.storeStorageUsed = exports.loadStorageUsed = exports.storeStorageInfo = exports.loadStorageInfo = exports.storeStateInit = exports.loadStateInit = exports.storeSplitMergeInfo = exports.loadSplitMergeInfo = exports.storeSimpleLibrary = exports.loadSimpleLibrary = exports.loadShardStateUnsplit = exports.storeShardIdent = exports.loadShardIdent = exports.storeShardAccounts = exports.loadShardAccounts = exports.ShardAccountRefValue = exports.storeShardAccount = exports.loadShardAccount = exports.SendMode = exports.storeMessageRelaxed = exports.loadMessageRelaxed = exports.storeMessage = exports.loadMessage = exports.loadMasterchainStateExtra = exports.storeHashUpdate = exports.loadHashUpdate = exports.storeDepthBalanceInfo = exports.loadDepthBalanceInfo = exports.storeCurrencyCollection = exports.loadCurrencyCollection = exports.storeComputeSkipReason = exports.loadComputeSkipReason = exports.storeCommonMessageInfoRelaxed = exports.loadCommonMessageInfoRelaxed = exports.storeCommonMessageInfo = exports.loadCommonMessageInfo = exports.storeAccountStorage = exports.loadAccountStorage = exports.storeAccountStatusChange = exports.loadAccountStatusChange = exports.storeAccountStatus = exports.loadAccountStatus = exports.storeAccountState = exports.loadAccountState = exports.storeAccount = exports.loadAccount = exports.comment = exports.external = exports.internal = void 0; | ||
exports.storeTransactionsStoragePhase = exports.loadTransactionStoragePhase = exports.storeTransactionDescription = exports.loadTransactionDescription = exports.storeTransactionCreditPhase = exports.loadTransactionCreditPhase = exports.storeTransactionComputePhase = exports.loadTransactionComputePhase = exports.storeTransactionBouncePhase = exports.loadTransactionBouncePhase = exports.storeTransactionActionPhase = exports.loadTransactionActionPhase = exports.storeTransaction = exports.loadTransaction = exports.storeTickTock = exports.loadTickTock = exports.storeStorageUsedShort = void 0; | ||
exports.loadStorageInfo = exports.storeStateInit = exports.loadStateInit = exports.storeSplitMergeInfo = exports.loadSplitMergeInfo = exports.storeSimpleLibrary = exports.loadSimpleLibrary = exports.loadShardStateUnsplit = exports.storeShardIdent = exports.loadShardIdent = exports.storeShardAccounts = exports.loadShardAccounts = exports.ShardAccountRefValue = exports.storeShardAccount = exports.loadShardAccount = exports.SendMode = exports.storeMessageRelaxed = exports.loadMessageRelaxed = exports.storeMessage = exports.loadMessage = exports.loadMasterchainStateExtra = exports.storeHashUpdate = exports.loadHashUpdate = exports.storeDepthBalanceInfo = exports.loadDepthBalanceInfo = exports.storeCurrencyCollection = exports.loadCurrencyCollection = exports.storeComputeSkipReason = exports.loadComputeSkipReason = exports.storeCommonMessageInfoRelaxed = exports.loadCommonMessageInfoRelaxed = exports.storeCommonMessageInfo = exports.loadCommonMessageInfo = exports.storeOutList = exports.loadOutList = exports.storeOutAction = exports.loadOutAction = exports.storeAccountStorage = exports.loadAccountStorage = exports.storeAccountStatusChange = exports.loadAccountStatusChange = exports.storeAccountStatus = exports.loadAccountStatus = exports.storeAccountState = exports.loadAccountState = exports.storeAccount = exports.loadAccount = exports.comment = exports.external = exports.internal = void 0; | ||
exports.storeTransactionsStoragePhase = exports.loadTransactionStoragePhase = exports.storeTransactionDescription = exports.loadTransactionDescription = exports.storeTransactionCreditPhase = exports.loadTransactionCreditPhase = exports.storeTransactionComputePhase = exports.loadTransactionComputePhase = exports.storeTransactionBouncePhase = exports.loadTransactionBouncePhase = exports.storeTransactionActionPhase = exports.loadTransactionActionPhase = exports.storeTransaction = exports.loadTransaction = exports.storeTickTock = exports.loadTickTock = exports.storeStorageUsedShort = exports.loadStorageUsedShort = exports.storeStorageUsed = exports.loadStorageUsed = exports.storeStorageInfo = void 0; | ||
var _helpers_1 = require("./_helpers"); | ||
@@ -32,2 +32,7 @@ Object.defineProperty(exports, "internal", { enumerable: true, get: function () { return _helpers_1.internal; } }); | ||
Object.defineProperty(exports, "storeAccountStorage", { enumerable: true, get: function () { return AccountStorage_1.storeAccountStorage; } }); | ||
var OutList_1 = require("./OutList"); | ||
Object.defineProperty(exports, "loadOutAction", { enumerable: true, get: function () { return OutList_1.loadOutAction; } }); | ||
Object.defineProperty(exports, "storeOutAction", { enumerable: true, get: function () { return OutList_1.storeOutAction; } }); | ||
Object.defineProperty(exports, "loadOutList", { enumerable: true, get: function () { return OutList_1.loadOutList; } }); | ||
Object.defineProperty(exports, "storeOutList", { enumerable: true, get: function () { return OutList_1.storeOutList; } }); | ||
var CommonMessageInfo_1 = require("./CommonMessageInfo"); | ||
@@ -34,0 +39,0 @@ Object.defineProperty(exports, "loadCommonMessageInfo", { enumerable: true, get: function () { return CommonMessageInfo_1.loadCommonMessageInfo; } }); |
@@ -31,3 +31,3 @@ "use strict"; | ||
let mode = vmState.loadUint(8); | ||
let exitCode = vmState.loadUint(32); | ||
let exitCode = vmState.loadInt(32); | ||
let exitArg = vmState.loadBit() ? vmState.loadInt(32) : undefined; | ||
@@ -72,3 +72,3 @@ let vmSteps = vmState.loadUint(32); | ||
.storeUint(src.mode, 8) | ||
.storeUint(src.exitCode, 32) | ||
.storeInt(src.exitCode, 32) | ||
.store((b) => (src.exitArg !== undefined && src.exitArg !== null) ? b.storeBit(1).storeInt(src.exitArg, 32) : b.storeBit(0)) | ||
@@ -75,0 +75,0 @@ .storeUint(src.vmSteps, 32) |
{ | ||
"name": "ton-core", | ||
"version": "0.52.0", | ||
"version": "0.53.0", | ||
"main": "dist/index.js", | ||
@@ -5,0 +5,0 @@ "repository": "https://github.com/ton-core/ton-core.git", |
# 💎 ton-core | ||
## 🚨 Repository Deprecated and Moved! 🚨 | ||
**This repository has been deprecated and is no longer actively maintained.** We have moved our project to a new repository, which you can find here: [ton-org/ton-core](https://github.com/ton-org/ton-core). The new NPM package is available here: [@ton/core](https://www.npmjs.com/package/@ton/core) | ||
Please make sure to update your bookmarks and star the new repository to stay up-to-date with the latest developments and updates. This repository will be archived and eventually removed. | ||
**Thank you for your continued support!** | ||
___________ | ||
Core library that implements low level primitives of TON blockchain. | ||
@@ -13,6 +21,11 @@ | ||
[Documentation](https://ton-community.github.io/ton-core/) | ||
[Documentation](https://ton-core.github.io/ton-core/) | ||
## Acknowledgements | ||
This library is developed by the [Whales Corp.](https://tonwhales.com/) and maintained by [Dan Volkov](https://github.com/dvlkv). | ||
# License | ||
MIT |
@@ -16,2 +16,3 @@ /** | ||
let address3 = Address.parseRaw('0:2cf55953e92efbeadab7ba725c3f93a0b23f842cbba72d7b8e6f510a70e422e3'); | ||
let address4 = Address.parse('-1:3333333333333333333333333333333333333333333333333333333333333333'); | ||
expect(address1.isBounceable).toBe(false); | ||
@@ -30,2 +31,4 @@ expect(address2.isBounceable).toBe(true); | ||
expect(address3.toRawString()).toBe('0:2cf55953e92efbeadab7ba725c3f93a0b23f842cbba72d7b8e6f510a70e422e3'); | ||
expect(address4.workChain).toBe(-1); | ||
expect(address4.hash).toEqual(Buffer.from('3333333333333333333333333333333333333333333333333333333333333333', 'hex')); | ||
}); | ||
@@ -32,0 +35,0 @@ it('should serialize to friendly form', () => { |
@@ -95,3 +95,3 @@ /** | ||
// hash is not valid | ||
if (!/[a-f][0-9]+/.test(hash.toLowerCase())) { | ||
if (!/[a-f0-9]+/.test(hash.toLowerCase())) { | ||
return false; | ||
@@ -98,0 +98,0 @@ } |
@@ -13,2 +13,15 @@ /** | ||
describe('BitString', () => { | ||
let testOOB:(method: 'substring' | 'subbuffer' , bs:BitString, offset:number, length:number) => void; | ||
beforeAll(() =>{ | ||
testOOB = (method: 'substring' | 'subbuffer', bs:BitString, offset:number, length: number) =>{ | ||
try { | ||
let bs2 = bs[method](offset, length); | ||
throw(Error("Should fail")); | ||
} | ||
catch(e: any) { | ||
expect(e.message.endsWith('out of bounds')).toBe(true); | ||
} | ||
} | ||
}); | ||
it('should read bits', () => { | ||
@@ -51,2 +64,35 @@ let bs = new BitString(Buffer.from([0b10101010]), 0, 8); | ||
}); | ||
it('should do substrings', () => { | ||
let bs = new BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
let bs2 = bs.substring(0, 16); | ||
expect(bs2!.length).toBe(16); | ||
}); | ||
it('should do empty substrings with requested length 0', () => { | ||
let bs = new BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
let bs2 = bs.substring(bs.length, 0); | ||
expect(bs2!.length).toBe(0); | ||
}); | ||
it('should OOB when substring offset is out of bounds', () => { | ||
let bs = new BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
testOOB('substring', bs, bs.length + 1, 0); | ||
testOOB('substring', bs, -1, 0); | ||
}); | ||
it('should OOB when subbuffer offset is out of bounds', () => { | ||
let bs = new BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
testOOB('subbuffer', bs, bs.length + 1, 0); | ||
testOOB('subbuffer', bs, -1, 0); | ||
}); | ||
it('should OOB when offset is on the end of bitsring and length > 0', () =>{ | ||
let bs = new BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
testOOB('substring', bs, bs.length, 1); | ||
}); | ||
it('should do empty subbuffers with requested length 0', () => { | ||
let bs = new BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
let bs2 = bs.subbuffer(bs.length, 0); | ||
expect(bs2!.length).toBe(0); | ||
}); | ||
it('should OOB when offset is on the end of buffer and length > 0', () => { | ||
let bs = new BitString(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), 0, 64); | ||
testOOB('subbuffer', bs, bs.length, 1); | ||
}); | ||
it('should process monkey strings', () => { | ||
@@ -122,2 +168,2 @@ let cases = [ | ||
}); | ||
}); | ||
}); |
@@ -28,2 +28,10 @@ /** | ||
/** | ||
* Checks if supplied object is BitString | ||
* @param src is unknow object | ||
* @returns true if object is BitString and false otherwise | ||
**/ | ||
static isBitString(src: unknown): src is BitString { | ||
return src instanceof BitString; | ||
} | ||
/** | ||
* Constructing BitString from a buffer | ||
@@ -86,3 +94,3 @@ * @param data data that contains the bitstring data. NOTE: We are expecting this buffer to be NOT modified | ||
// Check offset | ||
if (offset >= this._length) { | ||
if (offset > this._length) { | ||
throw new Error(`Offset(${offset}) > ${this._length} is out of bounds`); | ||
@@ -116,3 +124,3 @@ } | ||
// Check offset | ||
if (offset >= this._length) { | ||
if (offset > this._length) { | ||
throw new Error(`Offset ${offset} is out of bounds`); | ||
@@ -181,4 +189,3 @@ } | ||
} | ||
[inspectSymbol] = () => this.toString() | ||
} |
@@ -29,2 +29,24 @@ /** | ||
return builder.buffer(); | ||
} | ||
} | ||
export function paddedBufferToBits(buff: Buffer) { | ||
let bitLen = 0; | ||
// Finding rightmost non-zero byte in the buffer | ||
for( let i = buff.length - 1; i >= 0; i--) { | ||
if(buff[i] !== 0) { | ||
const testByte = buff[i]; | ||
// Looking for a rightmost set padding bit | ||
let bitPos = testByte & -testByte; | ||
if((bitPos & 1) == 0) { | ||
// It's power of 2 (only one bit set) | ||
bitPos = Math.log2(bitPos) + 1; | ||
} | ||
if(i > 0){ | ||
// If we are dealing with more than 1 byte buffer | ||
bitLen = i << 3; //Number of full bytes * 8 | ||
} | ||
bitLen += 8 - bitPos; | ||
break; | ||
} | ||
} | ||
return new BitString(buff, 0, bitLen); | ||
} |
@@ -11,4 +11,7 @@ /** | ||
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"; | ||
@@ -87,2 +90,74 @@ function storeBits(builder: Builder, src: string) { | ||
}); | ||
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); | ||
for (let k = 1; k <= 5; k++) { | ||
const proof = d.generateMerkleProof(k); | ||
Cell.fromBoc(proof.toBoc()); | ||
expect(exoticMerkleProof(proof.bits, proof.refs).proofHash).toEqual( | ||
Buffer.from( | ||
'ee41b86bd71f8224ebd01848b4daf4cd46d3bfb3e119d8b865ce7c2802511de3', | ||
'hex' | ||
) | ||
); | ||
} | ||
}); | ||
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)); | ||
} | ||
}); | ||
}); |
@@ -13,3 +13,6 @@ /** | ||
import { Slice } from "../boc/Slice"; | ||
import { BitString } from "../boc/BitString"; | ||
import { Maybe } from "../utils/maybe"; | ||
import { generateMerkleProof } from "./generateMerkleProof"; | ||
import { generateMerkleUpdate } from "./generateMerkleUpdate"; | ||
import { parseDict } from "./parseDict"; | ||
@@ -19,3 +22,3 @@ import { serializeDict } from "./serializeDict"; | ||
export type DictionaryKeyTypes = Address | number | bigint | Buffer; | ||
export type DictionaryKeyTypes = Address | number | bigint | Buffer | BitString; | ||
@@ -87,2 +90,15 @@ export type DictionaryKey<K extends DictionaryKeyTypes> = { | ||
return createBufferKey(bytes); | ||
}, | ||
/** | ||
* Create BitString key | ||
* @param bits key length | ||
* @returns DictionaryKey<BitString> | ||
* Point is that Buffer has to be 8 bit aligned, | ||
* while key is TVM dictionary doesn't have to be | ||
* aligned at all. | ||
*/ | ||
BitString: (bits: number) => { | ||
return createBitStringKey(bits); | ||
} | ||
@@ -179,2 +195,13 @@ } | ||
/** | ||
* Create BitString value | ||
* @param requested bit length | ||
* @returns DictionaryValue<BitString> | ||
* Point is that Buffer is not applicable | ||
* when length is not 8 bit alligned. | ||
*/ | ||
BitString: (bits: number) => { | ||
return createBitStringValue(bits); | ||
}, | ||
/** | ||
* Create dictionary value | ||
@@ -371,2 +398,10 @@ * @param key | ||
} | ||
generateMerkleProof(key: K): Cell { | ||
return generateMerkleProof(this, key, this._key!) | ||
} | ||
generateMerkleUpdate(key: K, newValue: V): Cell { | ||
return generateMerkleUpdate(this, key, this._key!, newValue); | ||
} | ||
} | ||
@@ -480,2 +515,16 @@ | ||
function createBitStringKey(bits: number): DictionaryKey<BitString> { | ||
return { | ||
bits, | ||
serialize: (src) => { | ||
if(!BitString.isBitString(src)) | ||
throw Error('Key is not a BitString'); | ||
return beginCell().storeBits(src).endCell().beginParse().loadUintBig(bits); | ||
}, | ||
parse: (src) => { | ||
return beginCell().storeUint(src, bits).endCell().beginParse().loadBits(bits); | ||
} | ||
} | ||
} | ||
function createIntValue(bits: number): DictionaryValue<number> { | ||
@@ -603,2 +652,16 @@ return { | ||
} | ||
} | ||
} | ||
function createBitStringValue(bits: number): DictionaryValue<BitString> { | ||
return { | ||
serialize: (src, builder) => { | ||
if (src.length !== bits) { | ||
throw Error('Invalid BitString size'); | ||
} | ||
builder.storeBits(src); | ||
}, | ||
parse: (src) => { | ||
return src.loadBits(bits); | ||
} | ||
} | ||
} |
@@ -10,2 +10,3 @@ /** | ||
import { Address } from "../../address/Address"; | ||
import { BitString } from "../../boc/BitString"; | ||
import { testAddress } from "../../utils/testAddress"; | ||
@@ -39,2 +40,12 @@ import { deserializeInternalKey, serializeInternalKey } from "./internalKeySerializer"; | ||
}); | ||
}); | ||
it('should serialize bit strings', () => { | ||
let cs = [Buffer.from('00', 'hex'), Buffer.from('ff', 'hex'), Buffer.from('0f', 'hex'), Buffer.from('0f000011002233456611', 'hex')]; | ||
for (let c of cs) { | ||
for(let i = 0; i < c.length * 8 - 1; i++) { | ||
let bs = new BitString(c, 0, c.length * 8 - i); | ||
const res = deserializeInternalKey(serializeInternalKey(bs)) as BitString; | ||
expect(res.equals(bs)).toBe(true); | ||
} | ||
} | ||
}) | ||
}); |
@@ -10,2 +10,4 @@ /** | ||
import { Address } from "../../address/Address"; | ||
import { BitString } from "../../boc/BitString"; | ||
import { bitsToPaddedBuffer, paddedBufferToBits } from "../../boc/utils/paddedBits"; | ||
@@ -24,2 +26,4 @@ export function serializeInternalKey(value: any): string { | ||
return 'f:' + value.toString('hex'); | ||
} else if(BitString.isBitString(value)) { | ||
return 'B:' + value.toString(); | ||
} else { | ||
@@ -42,3 +46,22 @@ throw Error('Invalid key type'); | ||
} | ||
else if (k === 'B:') { | ||
const lastDash = v.slice(-1) == "_"; | ||
const isPadded = lastDash || v.length % 2 != 0; | ||
if(isPadded) { | ||
let charLen = lastDash ? v.length - 1 : v.length; | ||
const padded = v.substr(0, charLen) + "0"; //Padding | ||
if((!lastDash) && ((charLen & 1) !== 0)){ | ||
// Four bit nibmle without padding | ||
return new BitString(Buffer.from(padded, 'hex'), 0, charLen << 2); | ||
} | ||
else { | ||
return paddedBufferToBits(Buffer.from(padded, 'hex')); | ||
} | ||
} | ||
else { | ||
return new BitString(Buffer.from(v, 'hex'), 0, v.length << 2); | ||
} | ||
} | ||
throw Error('Invalid key type: ' + k); | ||
} | ||
} |
@@ -35,2 +35,6 @@ /** | ||
// Merkle trees | ||
export { generateMerkleProof } from './dict/generateMerkleProof' | ||
export { generateMerkleUpdate } from './dict/generateMerkleUpdate' | ||
// Tuples | ||
@@ -37,0 +41,0 @@ export { Tuple, TupleItem, TupleItemNull, TupleItemInt, TupleItemNaN, TupleItemCell, TupleItemSlice, TupleItemBuilder } from './tuple/tuple'; |
/** | ||
* Copyright (c) Whales Corp. | ||
* Copyright (c) Whales Corp. | ||
* All Rights Reserved. | ||
@@ -40,2 +40,11 @@ * | ||
export { | ||
OutActionSendMsg, | ||
OutActionSetCode, | ||
OutAction, | ||
loadOutAction, | ||
storeOutAction, | ||
loadOutList, | ||
storeOutList | ||
} from './OutList'; | ||
export { | ||
CommonMessageInfo, | ||
@@ -193,2 +202,2 @@ CommonMessageInfoInternal, | ||
storeTransactionsStoragePhase | ||
} from './TransactionStoragePhase'; | ||
} from './TransactionStoragePhase'; |
@@ -66,3 +66,3 @@ /** | ||
let mode = vmState.loadUint(8); | ||
let exitCode = vmState.loadUint(32); | ||
let exitCode = vmState.loadInt(32); | ||
let exitArg = vmState.loadBit() ? vmState.loadInt(32) : undefined; | ||
@@ -107,3 +107,3 @@ let vmSteps = vmState.loadUint(32); | ||
.storeUint(src.mode, 8) | ||
.storeUint(src.exitCode, 32) | ||
.storeInt(src.exitCode, 32) | ||
.store((b) => (src.exitArg !== undefined && src.exitArg !== null) ? b.storeBit(1).storeInt(src.exitArg, 32) : b.storeBit(0)) | ||
@@ -115,2 +115,2 @@ .storeUint(src.vmSteps, 32) | ||
} | ||
} | ||
} |
1864060
373
24742
31