forked from ton-core/ton-core
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from Gusarich/patch2
add `generateMerkleProof` and `generateMerkleUpdate` functions for dictionaries
- Loading branch information
Showing
7 changed files
with
4,982 additions
and
6,844 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { beginCell } from '../boc/Builder'; | ||
import { Cell } from '../boc/Cell'; | ||
import { Slice } from '../boc/Slice'; | ||
import { DictionaryKeyTypes, Dictionary, DictionaryKey } from './Dictionary'; | ||
import { readUnaryLength } from './utils/readUnaryLength'; | ||
|
||
function convertToPrunedBranch(c: Cell): Cell { | ||
return new Cell({ | ||
exotic: true, | ||
bits: beginCell() | ||
.storeUint(1, 8) | ||
.storeUint(1, 8) | ||
.storeBuffer(c.hash(0)) | ||
.storeUint(c.depth(0), 16) | ||
.endCell() | ||
.beginParse() | ||
.loadBits(288), | ||
}); | ||
} | ||
|
||
function convertToMerkleProof(c: Cell): Cell { | ||
return new Cell({ | ||
exotic: true, | ||
bits: beginCell() | ||
.storeUint(3, 8) | ||
.storeBuffer(c.hash(0)) | ||
.storeUint(c.depth(0), 16) | ||
.endCell() | ||
.beginParse() | ||
.loadBits(280), | ||
refs: [c], | ||
}); | ||
} | ||
|
||
function doGenerateMerkleProof( | ||
prefix: string, | ||
slice: Slice, | ||
n: number, | ||
key: string | ||
): Cell { | ||
// Reading label | ||
const originalCell = slice.asCell(); | ||
|
||
let lb0 = slice.loadBit() ? 1 : 0; | ||
let prefixLength = 0; | ||
let pp = prefix; | ||
|
||
if (lb0 === 0) { | ||
// Short label detected | ||
|
||
// Read | ||
prefixLength = readUnaryLength(slice); | ||
|
||
// Read prefix | ||
for (let i = 0; i < prefixLength; i++) { | ||
pp += slice.loadBit() ? '1' : '0'; | ||
} | ||
} else { | ||
let lb1 = slice.loadBit() ? 1 : 0; | ||
if (lb1 === 0) { | ||
// Long label detected | ||
prefixLength = slice.loadUint(Math.ceil(Math.log2(n + 1))); | ||
for (let i = 0; i < prefixLength; i++) { | ||
pp += slice.loadBit() ? '1' : '0'; | ||
} | ||
} else { | ||
// Same label detected | ||
let bit = slice.loadBit() ? '1' : '0'; | ||
prefixLength = slice.loadUint(Math.ceil(Math.log2(n + 1))); | ||
for (let i = 0; i < prefixLength; i++) { | ||
pp += bit; | ||
} | ||
} | ||
} | ||
|
||
if (n - prefixLength === 0) { | ||
return originalCell; | ||
} else { | ||
let sl = originalCell.beginParse(); | ||
let left = sl.loadRef(); | ||
let right = sl.loadRef(); | ||
// NOTE: Left and right branches are implicitly contain prefixes '0' and '1' | ||
if (!left.isExotic) { | ||
if (pp + '0' === key.slice(0, pp.length + 1)) { | ||
left = doGenerateMerkleProof( | ||
pp + '0', | ||
left.beginParse(), | ||
n - prefixLength - 1, | ||
key | ||
); | ||
} else { | ||
left = convertToPrunedBranch(left); | ||
} | ||
} | ||
if (!right.isExotic) { | ||
if (pp + '1' === key.slice(0, pp.length + 1)) { | ||
right = doGenerateMerkleProof( | ||
pp + '1', | ||
right.beginParse(), | ||
n - prefixLength - 1, | ||
key | ||
); | ||
} else { | ||
right = convertToPrunedBranch(right); | ||
} | ||
} | ||
|
||
return beginCell() | ||
.storeSlice(sl) | ||
.storeRef(left) | ||
.storeRef(right) | ||
.endCell(); | ||
} | ||
} | ||
|
||
export function generateMerkleProof<K extends DictionaryKeyTypes, V>( | ||
dict: Dictionary<K, V>, | ||
key: K, | ||
keyObject: DictionaryKey<K> | ||
): Cell { | ||
const s = beginCell().storeDictDirect(dict).endCell().beginParse(); | ||
return convertToMerkleProof( | ||
doGenerateMerkleProof( | ||
'', | ||
s, | ||
keyObject.bits, | ||
keyObject.serialize(key).toString(2).padStart(keyObject.bits, '0') | ||
) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { beginCell } from '../boc/Builder'; | ||
import { Cell } from '../boc/Cell'; | ||
import { DictionaryKeyTypes, Dictionary, DictionaryKey } from './Dictionary'; | ||
import { generateMerkleProof } from './generateMerkleProof'; | ||
|
||
function convertToMerkleUpdate(c1: Cell, c2: Cell): Cell { | ||
return new Cell({ | ||
exotic: true, | ||
bits: beginCell() | ||
.storeUint(4, 8) | ||
.storeBuffer(c1.hash(0)) | ||
.storeBuffer(c2.hash(0)) | ||
.storeUint(c1.depth(0), 16) | ||
.storeUint(c2.depth(0), 16) | ||
.endCell() | ||
.beginParse() | ||
.loadBits(552), | ||
refs: [c1, c2], | ||
}); | ||
} | ||
|
||
export function generateMerkleUpdate<K extends DictionaryKeyTypes, V>( | ||
dict: Dictionary<K, V>, | ||
key: K, | ||
keyObject: DictionaryKey<K>, | ||
newValue: V | ||
): Cell { | ||
const oldProof = generateMerkleProof(dict, key, keyObject).refs[0]; | ||
dict.set(key, newValue); | ||
const newProof = generateMerkleProof(dict, key, keyObject).refs[0]; | ||
return convertToMerkleUpdate(oldProof, newProof); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Slice } from '../../boc/Slice'; | ||
|
||
export function readUnaryLength(slice: Slice) { | ||
let res = 0; | ||
while (slice.loadBit()) { | ||
res++; | ||
} | ||
return res; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.